diff options
768 files changed, 17660 insertions, 5675 deletions
diff --git a/DREAM_MANAGER_OWNERS b/DREAM_MANAGER_OWNERS new file mode 100644 index 000000000000..48bde6024cba --- /dev/null +++ b/DREAM_MANAGER_OWNERS @@ -0,0 +1 @@ +brycelee@google.com diff --git a/Ravenwood.bp b/Ravenwood.bp index 74b34fbcf2a1..412f2b746887 100644 --- a/Ravenwood.bp +++ b/Ravenwood.bp @@ -104,6 +104,18 @@ genrule { ], } +genrule { + name: "framework-minus-apex.ravenwood.keep_all", + defaults: ["ravenwood-internal-only-visibility-genrule"], + cmd: "cp $(in) $(out)", + srcs: [ + ":framework-minus-apex.ravenwood-base{hoststubgen_keep_all.txt}", + ], + out: [ + "hoststubgen_framework-minus-apex_keep_all.txt", + ], +} + java_library { name: "services.core-for-hoststubgen", installable: false, // host only jar. @@ -189,6 +201,18 @@ genrule { ], } +genrule { + name: "services.core.ravenwood.keep_all", + defaults: ["ravenwood-internal-only-visibility-genrule"], + cmd: "cp $(in) $(out)", + srcs: [ + ":services.core.ravenwood-base{hoststubgen_keep_all.txt}", + ], + out: [ + "hoststubgen_services.core_keep_all.txt", + ], +} + java_library { name: "services.core.ravenwood-jarjar", installable: false, diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 77b74e9898b8..5adcd930e341 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -707,11 +707,11 @@ void BootAnimation::resizeSurface(int newWidth, int newHeight) { eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroySurface(mDisplay, mSurface); - mFlingerSurfaceControl->updateDefaultBufferSize(newWidth, newHeight); const auto limitedSize = limitSurfaceSize(newWidth, newHeight); mWidth = limitedSize.width; mHeight = limitedSize.height; + mFlingerSurfaceControl->updateDefaultBufferSize(mWidth, mHeight); EGLConfig config = getEglConfig(mDisplay); EGLSurface surface = eglCreateWindowSurface(mDisplay, config, mFlingerSurface.get(), nullptr); if (eglMakeCurrent(mDisplay, surface, surface, mContext) == EGL_FALSE) { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index ba1bcc8852c9..96315ebccc49 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -1143,16 +1143,13 @@ package android.app { field public static final int NAV_BAR_MODE_KIDS = 1; // 0x1 } - public static final class StatusBarManager.DisableInfo implements android.os.Parcelable { + public static final class StatusBarManager.DisableInfo { method public boolean areAllComponentsEnabled(); - method public int describeContents(); method public boolean isNavigateToHomeDisabled(); method public boolean isNotificationPeekingDisabled(); method public boolean isRecentsDisabled(); method public boolean isSearchDisabled(); method public boolean isStatusBarExpansionDisabled(); - method public void writeToParcel(@NonNull android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.app.StatusBarManager.DisableInfo> CREATOR; } public final class SystemServiceRegistry { diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt index 62fc67b8dedf..78577e2b4090 100644 --- a/core/api/system-lint-baseline.txt +++ b/core/api/system-lint-baseline.txt @@ -1939,10 +1939,6 @@ UnflaggedApi: android.app.ActivityManager#getExternalHistoricalProcessStartReaso New API must be flagged with @FlaggedApi: method android.app.ActivityManager.getExternalHistoricalProcessStartReasons(String,int) UnflaggedApi: android.app.AppOpsManager#OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO: New API must be flagged with @FlaggedApi: field android.app.AppOpsManager.OPSTR_RECEIVE_SANDBOX_TRIGGER_AUDIO -UnflaggedApi: android.app.StatusBarManager.DisableInfo#CREATOR: - New API must be flagged with @FlaggedApi: field android.app.StatusBarManager.DisableInfo.CREATOR -UnflaggedApi: android.app.StatusBarManager.DisableInfo#isBackDisabled(): - New API must be flagged with @FlaggedApi: method android.app.StatusBarManager.DisableInfo.isBackDisabled() UnflaggedApi: android.companion.virtual.VirtualDeviceManager.VirtualDevice#getPersistentDeviceId(): New API must be flagged with @FlaggedApi: method android.companion.virtual.VirtualDeviceManager.VirtualDevice.getPersistentDeviceId() UnflaggedApi: android.content.Context#THREAD_NETWORK_SERVICE: diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 211fc961196c..624227dc26f3 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -463,7 +463,7 @@ package android.app { method @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void togglePanel(); } - public static final class StatusBarManager.DisableInfo implements android.os.Parcelable { + public static final class StatusBarManager.DisableInfo { method public boolean isRotationSuggestionDisabled(); } diff --git a/core/java/android/app/AppCompatTaskInfo.java b/core/java/android/app/AppCompatTaskInfo.java index 7724c2369954..92543b1c7646 100644 --- a/core/java/android/app/AppCompatTaskInfo.java +++ b/core/java/android/app/AppCompatTaskInfo.java @@ -32,6 +32,11 @@ public class AppCompatTaskInfo implements Parcelable { public boolean topActivityEligibleForLetterboxEducation; /** + * Whether the letterbox education is enabled + */ + public boolean isLetterboxEducationEnabled; + + /** * Whether the direct top activity is in size compat mode on foreground. */ public boolean topActivityInSizeCompat; @@ -178,6 +183,7 @@ public class AppCompatTaskInfo implements Parcelable { == that.topActivityEligibleForUserAspectRatioButton && topActivityEligibleForLetterboxEducation == that.topActivityEligibleForLetterboxEducation + && isLetterboxEducationEnabled == that.isLetterboxEducationEnabled && topActivityLetterboxVerticalPosition == that.topActivityLetterboxVerticalPosition && topActivityLetterboxHorizontalPosition == that.topActivityLetterboxHorizontalPosition @@ -192,6 +198,7 @@ public class AppCompatTaskInfo implements Parcelable { * Reads the AppCompatTaskInfo from a parcel. */ void readFromParcel(Parcel source) { + isLetterboxEducationEnabled = source.readBoolean(); topActivityInSizeCompat = source.readBoolean(); topActivityEligibleForLetterboxEducation = source.readBoolean(); isLetterboxDoubleTapEnabled = source.readBoolean(); @@ -212,6 +219,7 @@ public class AppCompatTaskInfo implements Parcelable { */ @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(isLetterboxEducationEnabled); dest.writeBoolean(topActivityInSizeCompat); dest.writeBoolean(topActivityEligibleForLetterboxEducation); dest.writeBoolean(isLetterboxDoubleTapEnabled); @@ -232,6 +240,7 @@ public class AppCompatTaskInfo implements Parcelable { return "AppCompatTaskInfo { topActivityInSizeCompat=" + topActivityInSizeCompat + " topActivityEligibleForLetterboxEducation= " + topActivityEligibleForLetterboxEducation + + "isLetterboxEducationEnabled= " + isLetterboxEducationEnabled + " isLetterboxDoubleTapEnabled= " + isLetterboxDoubleTapEnabled + " topActivityEligibleForUserAspectRatioButton= " + topActivityEligibleForUserAspectRatioButton diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 2d0f6fccb8f2..54f69099e081 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -482,7 +482,8 @@ public class AppOpsManager { UID_STATE_FOREGROUND_SERVICE, UID_STATE_FOREGROUND, UID_STATE_BACKGROUND, - UID_STATE_CACHED + UID_STATE_CACHED, + UID_STATE_NONEXISTENT }) public @interface UidState {} @@ -566,6 +567,12 @@ public class AppOpsManager { public static final int MIN_PRIORITY_UID_STATE = UID_STATE_CACHED; /** + * Special uid state: The UID is not running + * @hide + */ + public static final int UID_STATE_NONEXISTENT = Integer.MAX_VALUE; + + /** * Resolves the first unrestricted state given an app op. * @param op The op to resolve. * @return The last restricted UID state. @@ -596,6 +603,7 @@ public class AppOpsManager { UID_STATE_FOREGROUND, UID_STATE_BACKGROUND, UID_STATE_CACHED + // UID_STATE_NONEXISTENT isn't a real UID state, so it is excluded }; /** @hide */ @@ -615,6 +623,8 @@ public class AppOpsManager { return "bg"; case UID_STATE_CACHED: return "cch"; + case UID_STATE_NONEXISTENT: + return "gone"; default: return "unknown"; } diff --git a/core/java/android/app/DreamManager.java b/core/java/android/app/DreamManager.java index ef6982e4a13c..4ac40a1f77b2 100644 --- a/core/java/android/app/DreamManager.java +++ b/core/java/android/app/DreamManager.java @@ -18,6 +18,7 @@ package android.app; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; +import android.annotation.FlaggedApi; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemService; @@ -30,6 +31,7 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.provider.Settings; import android.service.dreams.DreamService; +import android.service.dreams.Flags; import android.service.dreams.IDreamManager; /** @@ -217,4 +219,19 @@ public class DreamManager { } return false; } + + /** + * Sets whether the dream is obscured by something. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_DREAM_HANDLES_BEING_OBSCURED) + @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) + public void setDreamIsObscured(boolean isObscured) { + try { + mService.setDreamIsObscured(isObscured); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 0caea7f8084c..9c806593b57d 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -7155,13 +7155,7 @@ public class Notification implements Parcelable // Adds any new extras provided by the user. if (mUserExtras != null) { final Bundle saveExtras = (Bundle) mUserExtras.clone(); - if (SystemProperties.getBoolean( - "persist.sysui.notification.builder_extras_override", false)) { - mN.extras.putAll(saveExtras); - } else { - saveExtras.putAll(mN.extras); - mN.extras = saveExtras; - } + mN.extras.putAll(saveExtras); } if (!Flags.sortSectionByTime()) { diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index 97c2e43a1db6..2e38c06a7479 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -60,6 +60,9 @@ per-file ReceiverInfo* = file:/BROADCASTS_OWNERS # ComponentCaller per-file ComponentCaller.java = file:COMPONENT_CALLER_OWNERS +# DreamManager +per-file DreamManager.java = file:/DREAM_MANAGER_OWNERS + # GrammaticalInflectionManager per-file *GrammaticalInflection* = file:/services/core/java/com/android/server/grammaticalinflection/OWNERS per-file grammatical_inflection_manager.aconfig = file:/services/core/java/com/android/server/grammaticalinflection/OWNERS diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java index 301fef877d6c..14195c473c6d 100644 --- a/core/java/android/app/StatusBarManager.java +++ b/core/java/android/app/StatusBarManager.java @@ -21,7 +21,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -44,7 +43,6 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.IBinder; -import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -59,7 +57,6 @@ import com.android.internal.statusbar.IAddTileResultCallback; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.IUndoMediaTransferCallback; import com.android.internal.statusbar.NotificationVisibility; -import com.android.internal.util.DataClass; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -632,49 +629,38 @@ public class StatusBarManager { } /** - * @deprecated - * Disable some features in the status bar. Pass the bitwise-or of the DISABLE_* - * flags. To re-enable everything, pass {@link #DISABLE_NONE}. - * - * This method is deprecated and callers should use - * {@link #requestDisabledComponent(DisableInfo, String)} + * Disable some features in the status bar. Pass the bitwise-or of the DISABLE_* flags. + * To re-enable everything, pass {@link #DISABLE_NONE}. * * @hide */ - @Deprecated @UnsupportedAppUsage public void disable(int what) { - requestDisabledComponent(new DisableInfo(what & DISABLE_MASK, what & DISABLE2_MASK), null); + try { + final int userId = Binder.getCallingUserHandle().getIdentifier(); + final IStatusBarService svc = getService(); + if (svc != null) { + svc.disableForUser(what, mToken, mContext.getPackageName(), userId); + } + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } } /** - * @deprecated - * Disable some features in the status bar. Pass the bitwise-or of the DISABLE_2* - * flags. To re-enable everything, pass {@link #DISABLE2_NONE}. + * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags. + * To re-enable everything, pass {@link #DISABLE_NONE}. * - * This method is deprecated and callers should use - * {@link #requestDisabledComponent(DisableInfo, String)} + * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. * * @hide */ - @Deprecated - @UnsupportedAppUsage - public void disable2(int what) { - requestDisabledComponent(new DisableInfo(what & DISABLE_MASK, what & DISABLE2_MASK), null); - } - - /** - * Disable some features in the status bar. Pass a DisableInfo object with the required flags. - * - * @hide - */ - @UnsupportedAppUsage - public void requestDisabledComponent(DisableInfo disableInfo, String reason) { + public void disable2(@Disable2Flags int what) { try { final int userId = Binder.getCallingUserHandle().getIdentifier(); final IStatusBarService svc = getService(); if (svc != null) { - svc.disableForUser(disableInfo, mToken, mContext.getPackageName(), userId, reason); + svc.disable2ForUser(what, mToken, mContext.getPackageName(), userId); } } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); @@ -902,9 +888,18 @@ public class StatusBarManager { @SystemApi @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setDisabledForSetup(boolean disabled) { - int flags1 = disabled ? DEFAULT_SETUP_DISABLE_FLAGS : DISABLE_NONE; - DisableInfo info = new DisableInfo(flags1, DISABLE2_NONE); - requestDisabledComponent(info, "setDisabledForSetup"); + try { + final int userId = Binder.getCallingUserHandle().getIdentifier(); + final IStatusBarService svc = getService(); + if (svc != null) { + svc.disableForUser(disabled ? DEFAULT_SETUP_DISABLE_FLAGS : DISABLE_NONE, + mToken, mContext.getPackageName(), userId); + svc.disable2ForUser(disabled ? DEFAULT_SETUP_DISABLE2_FLAGS : DISABLE2_NONE, + mToken, mContext.getPackageName(), userId); + } + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } } /** @@ -919,9 +914,16 @@ public class StatusBarManager { @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(android.Manifest.permission.STATUS_BAR) public void setExpansionDisabledForSimNetworkLock(boolean disabled) { - int flags1 = disabled ? DEFAULT_SIM_LOCKED_DISABLED_FLAGS : DISABLE_NONE; - DisableInfo info = new DisableInfo(flags1, DISABLE2_NONE); - requestDisabledComponent(info, "setExpansionDisabledForSimNetworkLock"); + try { + final int userId = Binder.getCallingUserHandle().getIdentifier(); + final IStatusBarService svc = getService(); + if (svc != null) { + svc.disableForUser(disabled ? DEFAULT_SIM_LOCKED_DISABLED_FLAGS : DISABLE_NONE, + mToken, mContext.getPackageName(), userId); + } + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } } /** @@ -1313,75 +1315,33 @@ public class StatusBarManager { * @hide */ @SystemApi - @DataClass - public static final class DisableInfo implements Parcelable { + public static final class DisableInfo { - /** - * @hide - */ private boolean mStatusBarExpansion; - /** - * @hide - */ private boolean mNavigateHome; - /** - * @hide - */ private boolean mNotificationPeeking; - /** - * @hide - */ private boolean mRecents; - /** - * @hide - */ - private boolean mBack; - /** - * @hide - */ private boolean mSearch; - /** - * @hide - */ private boolean mSystemIcons; - /** - * @hide - */ private boolean mClock; - /** - * @hide - */ private boolean mNotificationIcons; - /** - * @hide - */ private boolean mRotationSuggestion; - /** - * @hide - */ - private boolean mNotificationTicker; /** @hide */ - @SuppressLint("UnflaggedApi") public DisableInfo(int flags1, int flags2) { mStatusBarExpansion = (flags1 & DISABLE_EXPAND) != 0; mNavigateHome = (flags1 & DISABLE_HOME) != 0; mNotificationPeeking = (flags1 & DISABLE_NOTIFICATION_ALERTS) != 0; mRecents = (flags1 & DISABLE_RECENT) != 0; - mBack = (flags1 & DISABLE_BACK) != 0; mSearch = (flags1 & DISABLE_SEARCH) != 0; mSystemIcons = (flags1 & DISABLE_SYSTEM_INFO) != 0; mClock = (flags1 & DISABLE_CLOCK) != 0; mNotificationIcons = (flags1 & DISABLE_NOTIFICATION_ICONS) != 0; - mNotificationTicker = (flags1 & DISABLE_NOTIFICATION_TICKER) != 0; mRotationSuggestion = (flags2 & DISABLE2_ROTATE_SUGGESTIONS) != 0; } /** @hide */ - @SuppressLint("UnflaggedApi") - public DisableInfo() { - setEnableAll(); - } + public DisableInfo() {} /** * @return {@code true} if expanding the notification shade is disabled @@ -1409,7 +1369,7 @@ public class StatusBarManager { } /** * @hide */ - public void setNavigationHomeDisabled(boolean disabled) { + public void setNagivationHomeDisabled(boolean disabled) { mNavigateHome = disabled; } @@ -1444,20 +1404,6 @@ public class StatusBarManager { } /** - * @return {@code true} if mBack is disabled - * - * @hide - */ - public boolean isBackDisabled() { - return mBack; - } - - /** @hide */ - public void setBackDisabled(boolean disabled) { - mBack = disabled; - } - - /** * @return {@code true} if mSearch is disabled * * @hide @@ -1515,20 +1461,6 @@ public class StatusBarManager { } /** - * @return {@code true} if notification ticker is disabled - * - * @hide - */ - public boolean isNotificationTickerDisabled() { - return mNotificationTicker; - } - - /** * @hide */ - public void setNotificationTickerDisabled(boolean disabled) { - mNotificationTicker = disabled; - } - - /** * Returns whether the rotation suggestion is disabled. * * @hide @@ -1538,11 +1470,6 @@ public class StatusBarManager { return mRotationSuggestion; } - /** * @hide */ - public void setRotationSuggestionDisabled(boolean disabled) { - mNotificationIcons = disabled; - } - /** * @return {@code true} if no components are disabled (default state) * @hide @@ -1550,8 +1477,8 @@ public class StatusBarManager { @SystemApi public boolean areAllComponentsEnabled() { return !mStatusBarExpansion && !mNavigateHome && !mNotificationPeeking && !mRecents - && !mBack && !mSearch && !mSystemIcons && !mClock && !mNotificationIcons - && !mNotificationTicker && !mRotationSuggestion; + && !mSearch && !mSystemIcons && !mClock && !mNotificationIcons + && !mRotationSuggestion; } /** @hide */ @@ -1560,12 +1487,10 @@ public class StatusBarManager { mNavigateHome = false; mNotificationPeeking = false; mRecents = false; - mBack = false; mSearch = false; mSystemIcons = false; mClock = false; mNotificationIcons = false; - mNotificationTicker = false; mRotationSuggestion = false; } @@ -1575,9 +1500,9 @@ public class StatusBarManager { * @hide */ public boolean areAllComponentsDisabled() { - return mStatusBarExpansion && mNavigateHome && mNotificationPeeking && mRecents && mBack - && mSearch && mSystemIcons && mClock && mNotificationIcons - && mNotificationTicker && mRotationSuggestion; + return mStatusBarExpansion && mNavigateHome && mNotificationPeeking + && mRecents && mSearch && mSystemIcons && mClock && mNotificationIcons + && mRotationSuggestion; } /** @hide */ @@ -1586,12 +1511,10 @@ public class StatusBarManager { mNavigateHome = true; mNotificationPeeking = true; mRecents = true; - mBack = true; mSearch = true; mSystemIcons = true; mClock = true; mNotificationIcons = true; - mNotificationTicker = true; mRotationSuggestion = true; } @@ -1599,19 +1522,16 @@ public class StatusBarManager { @Override public String toString() { StringBuilder sb = new StringBuilder(); - - sb.append("Disable Info: "); + sb.append("DisableInfo: "); sb.append(" mStatusBarExpansion=").append(mStatusBarExpansion ? "disabled" : "enabled"); sb.append(" mNavigateHome=").append(mNavigateHome ? "disabled" : "enabled"); sb.append(" mNotificationPeeking=") .append(mNotificationPeeking ? "disabled" : "enabled"); sb.append(" mRecents=").append(mRecents ? "disabled" : "enabled"); - sb.append(" mBack=").append(mBack ? "disabled" : "enabled"); sb.append(" mSearch=").append(mSearch ? "disabled" : "enabled"); sb.append(" mSystemIcons=").append(mSystemIcons ? "disabled" : "enabled"); sb.append(" mClock=").append(mClock ? "disabled" : "enabled"); sb.append(" mNotificationIcons=").append(mNotificationIcons ? "disabled" : "enabled"); - sb.append(" mNotificationTicker=").append(mNotificationTicker ? "disabled" : "enabled"); sb.append(" mRotationSuggestion=").append(mRotationSuggestion ? "disabled" : "enabled"); return sb.toString(); @@ -1619,7 +1539,7 @@ public class StatusBarManager { } /** - * Convert a DisableInfo to equivalent flags. + * Convert a DisableInfo to equivalent flags * @return a pair of equivalent disable flags * * @hide @@ -1632,278 +1552,14 @@ public class StatusBarManager { if (mNavigateHome) disable1 |= DISABLE_HOME; if (mNotificationPeeking) disable1 |= DISABLE_NOTIFICATION_ALERTS; if (mRecents) disable1 |= DISABLE_RECENT; - if (mBack) disable1 |= DISABLE_BACK; if (mSearch) disable1 |= DISABLE_SEARCH; if (mSystemIcons) disable1 |= DISABLE_SYSTEM_INFO; if (mClock) disable1 |= DISABLE_CLOCK; if (mNotificationIcons) disable1 |= DISABLE_NOTIFICATION_ICONS; - if (mNotificationTicker) disable1 |= DISABLE_NOTIFICATION_TICKER; if (mRotationSuggestion) disable2 |= DISABLE2_ROTATE_SUGGESTIONS; return new Pair<Integer, Integer>(disable1, disable2); } - - - - // Code below generated by codegen v1.0.23. - // - // DO NOT MODIFY! - // CHECKSTYLE:OFF Generated code - // - // To regenerate run: - // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/app/StatusBarManager.java - // - // To exclude the generated code from IntelliJ auto-formatting enable (one-time): - // Settings > Editor > Code Style > Formatter Control - //@formatter:off - - - /** - * Creates a new DisableInfo. - * @hide - */ - @DataClass.Generated.Member - public DisableInfo( - boolean statusBarExpansion, - boolean navigateHome, - boolean notificationPeeking, - boolean recents, - boolean back, - boolean search, - boolean systemIcons, - boolean clock, - boolean notificationIcons, - boolean rotationSuggestion, - boolean notificationTicker) { - this.mStatusBarExpansion = statusBarExpansion; - this.mNavigateHome = navigateHome; - this.mNotificationPeeking = notificationPeeking; - this.mRecents = recents; - this.mBack = back; - this.mSearch = search; - this.mSystemIcons = systemIcons; - this.mClock = clock; - this.mNotificationIcons = notificationIcons; - this.mRotationSuggestion = rotationSuggestion; - this.mNotificationTicker = notificationTicker; - - // onConstructed(); // You can define this method to get a callback - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isStatusBarExpansion() { - return mStatusBarExpansion; - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isNavigateHome() { - return mNavigateHome; - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isNotificationPeeking() { - return mNotificationPeeking; - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isRecents() { - return mRecents; - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isBack() { - return mBack; - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isSearch() { - return mSearch; - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isSystemIcons() { - return mSystemIcons; - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isClock() { - return mClock; - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isNotificationIcons() { - return mNotificationIcons; - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isRotationSuggestion() { - return mRotationSuggestion; - } - - /** - * @hide - */ - @DataClass.Generated.Member - public boolean isNotificationTicker() { - return mNotificationTicker; - } - - /** - * @hide - */ - @SuppressLint("UnflaggedApi") - @Override - @DataClass.Generated.Member - public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { - // You can override field parcelling by defining methods like: - // void parcelFieldName(Parcel dest, int flags) { ... } - - int flg = 0; - if (mStatusBarExpansion) flg |= 0x1; - if (mNavigateHome) flg |= 0x2; - if (mNotificationPeeking) flg |= 0x4; - if (mRecents) flg |= 0x8; - if (mBack) flg |= 0x10; - if (mSearch) flg |= 0x20; - if (mSystemIcons) flg |= 0x40; - if (mClock) flg |= 0x80; - if (mNotificationIcons) flg |= 0x100; - if (mRotationSuggestion) flg |= 0x200; - if (mNotificationTicker) flg |= 0x400; - dest.writeInt(flg); - } - - /** - * @hide - */ - @SuppressLint("UnflaggedApi") - @Override - @DataClass.Generated.Member - public int describeContents() { return 0; } - - /** @hide */ - @SuppressWarnings({"unchecked", "RedundantCast"}) - @DataClass.Generated.Member - /* package-private */ DisableInfo(@NonNull android.os.Parcel in) { - // You can override field unparcelling by defining methods like: - // static FieldType unparcelFieldName(Parcel in) { ... } - - int flg = in.readInt(); - boolean statusBarExpansion = (flg & 0x1) != 0; - boolean navigateHome = (flg & 0x2) != 0; - boolean notificationPeeking = (flg & 0x4) != 0; - boolean recents = (flg & 0x8) != 0; - boolean back = (flg & 0x10) != 0; - boolean search = (flg & 0x20) != 0; - boolean systemIcons = (flg & 0x40) != 0; - boolean clock = (flg & 0x80) != 0; - boolean notificationIcons = (flg & 0x100) != 0; - boolean rotationSuggestion = (flg & 0x200) != 0; - boolean notificationTicker = (flg & 0x400) != 0; - - this.mStatusBarExpansion = statusBarExpansion; - this.mNavigateHome = navigateHome; - this.mNotificationPeeking = notificationPeeking; - this.mRecents = recents; - this.mBack = back; - this.mSearch = search; - this.mSystemIcons = systemIcons; - this.mClock = clock; - this.mNotificationIcons = notificationIcons; - this.mRotationSuggestion = rotationSuggestion; - this.mNotificationTicker = notificationTicker; - - // onConstructed(); // You can define this method to get a callback - } - - @DataClass.Generated.Member - public static final @NonNull Parcelable.Creator<DisableInfo> CREATOR - = new Parcelable.Creator<DisableInfo>() { - @Override - public DisableInfo[] newArray(int size) { - return new DisableInfo[size]; - } - - @Override - public DisableInfo createFromParcel(@NonNull android.os.Parcel in) { - return new DisableInfo(in); - } - }; - - @DataClass.Generated( - time = 1708625947132L, - codegenVersion = "1.0.23", - sourceFile = "frameworks/base/core/java/android/app/StatusBarManager.java", - inputSignatures = "private boolean mStatusBarExpansion\nprivate boolean " - + "mNavigateHome\nprivate boolean mNotificationPeeking\nprivate " - + "boolean mRecents\nprivate boolean mBack\nprivate boolean mSearch\n" - + "private boolean mSystemIcons\nprivate boolean mClock\nprivate " - + "boolean mNotificationIcons\nprivate boolean mRotationSuggestion\n" - + "private boolean mNotificationTicker\npublic " - + "@android.annotation.SystemApi boolean isStatusBarExpansionDisabled()\n" - + "public void setStatusBarExpansionDisabled(boolean)\npublic " - + "@android.annotation.SystemApi boolean isNavigateToHomeDisabled()\npublic" - + " void setNavigationHomeDisabled(boolean)\npublic " - + "@android.annotation.SystemApi boolean isNotificationPeekingDisabled()" - + "\npublic void setNotificationPeekingDisabled(boolean)\npublic " - + "@android.annotation.SystemApi boolean isRecentsDisabled()\npublic " - + "void setRecentsDisabled(boolean)\npublic boolean isBackDisabled()" - + "\npublic void setBackDisabled(boolean)\npublic " - + "@android.annotation.SystemApi boolean isSearchDisabled()\npublic " - + "void setSearchDisabled(boolean)\npublic boolean " - + "areSystemIconsDisabled()\npublic void setSystemIconsDisabled(boolean)\n" - + "public boolean isClockDisabled()\npublic " - + "void setClockDisabled(boolean)\npublic boolean " - + "areNotificationIconsDisabled()\npublic void " - + "setNotificationIconsDisabled(boolean)\npublic boolean " - + "isNotificationTickerDisabled()\npublic void " - + "setNotificationTickerDisabled(boolean)\npublic " - + "@android.annotation.TestApi boolean isRotationSuggestionDisabled()\n" - + "public void setRotationSuggestionDisabled(boolean)\npublic " - + "@android.annotation.SystemApi boolean areAllComponentsEnabled()\npublic" - + " void setEnableAll()\npublic boolean areAllComponentsDisabled()\n" - + "public void setDisableAll()\npublic @android.annotation.NonNull " - + "@java.lang.Override java.lang.String toString()\npublic " - + "android.util.Pair<java.lang.Integer,java.lang.Integer> toFlags()\n" - + "class DisableInfo extends java.lang.Object implements " - + "[android.os.Parcelable]\n@com.android.internal.util.DataClass") - @Deprecated - private void __metadata() {} - - - //@formatter:on - // End of generated code - } /** diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 57b5c13a659d..3213b40b3437 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -1041,6 +1041,7 @@ public class AppWidgetManager { */ public AppWidgetProviderInfo getAppWidgetInfo(int appWidgetId) { if (mService == null) { + Log.e(TAG, "Service wasn't initialized, appWidgetId=" + appWidgetId); return null; } try { @@ -1048,6 +1049,9 @@ public class AppWidgetManager { if (info != null) { // Converting complex to dp. info.updateDimensions(mDisplayMetrics); + } else { + Log.e(TAG, "App widget provider info is null. PackageName=" + mPackageName + + " appWidgetId-" + appWidgetId); } return info; } catch (RemoteException e) { diff --git a/core/java/android/companion/flags.aconfig b/core/java/android/companion/flags.aconfig index 84588577b6d6..36d0e081af2a 100644 --- a/core/java/android/companion/flags.aconfig +++ b/core/java/android/companion/flags.aconfig @@ -39,3 +39,11 @@ flag { description: "Expose perm sync user consent API" bug: "309528663" } + +flag { + name: "ongoing_perm_sync" + is_exported: true + namespace: "companion" + description: "Enable ongoing perm sync" + bug: "338469649" +}
\ No newline at end of file diff --git a/core/java/android/content/pm/flags.aconfig b/core/java/android/content/pm/flags.aconfig index cee8d96fb0d7..061e7f711ba5 100644 --- a/core/java/android/content/pm/flags.aconfig +++ b/core/java/android/content/pm/flags.aconfig @@ -254,6 +254,14 @@ flag { } flag { + name: "wait_application_killed" + namespace: "package_manager_service" + description: "Feature flag to control whether to wait until the application is killed when clear application data" + bug: "31009094" + is_fixed_read_only: true +} + +flag { name: "component_state_changed_metrics" namespace: "package_manager_service" description: "Feature flag to log the metrics when the component state is changed." diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index a0e40f6390ee..61f1ee11e059 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -34,6 +34,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.TestApi; +import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.graphics.Bitmap; @@ -603,7 +604,6 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan mPromptInfo.setIsForLegacyFingerprintManager(sensorId); return this; } - // LINT.ThenChange(frameworks/base/core/java/android/hardware/biometrics/PromptInfo.java) /** * Set if emergency call button should show, for example if biometrics are @@ -613,12 +613,33 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan * @hide */ @NonNull + @RequiresPermission(anyOf = {TEST_BIOMETRIC, USE_BIOMETRIC_INTERNAL}) public Builder setShowEmergencyCallButton(boolean showEmergencyCallButton) { mPromptInfo.setShowEmergencyCallButton(showEmergencyCallButton); return this; } /** + * Set caller's component name for getting logo icon/description. This should only be used + * by ConfirmDeviceCredentialActivity, see b/337082634 for more context. + * + * @param componentNameForConfirmDeviceCredentialActivity set the component name for + * ConfirmDeviceCredentialActivity. + * @return This builder. + * @hide + */ + @NonNull + @RequiresPermission(anyOf = {TEST_BIOMETRIC, USE_BIOMETRIC_INTERNAL}) + public Builder setComponentNameForConfirmDeviceCredentialActivity( + ComponentName componentNameForConfirmDeviceCredentialActivity) { + mPromptInfo.setComponentNameForConfirmDeviceCredentialActivity( + componentNameForConfirmDeviceCredentialActivity); + return this; + } + + // LINT.ThenChange(frameworks/base/core/java/android/hardware/biometrics/PromptInfo.java) + + /** * Creates a {@link BiometricPrompt}. * * @return An instance of {@link BiometricPrompt}. diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java index 18b75c9b8f8f..bb07b9b881f8 100644 --- a/core/java/android/hardware/biometrics/PromptInfo.java +++ b/core/java/android/hardware/biometrics/PromptInfo.java @@ -19,6 +19,7 @@ package android.hardware.biometrics; import android.annotation.DrawableRes; import android.annotation.NonNull; import android.annotation.Nullable; +import android.content.ComponentName; import android.graphics.Bitmap; import android.os.Parcel; import android.os.Parcelable; @@ -56,6 +57,7 @@ public class PromptInfo implements Parcelable { private boolean mIsForLegacyFingerprintManager = false; private boolean mShowEmergencyCallButton = false; private boolean mUseParentProfileForDeviceCredential = false; + private ComponentName mComponentNameForConfirmDeviceCredentialActivity = null; public PromptInfo() { @@ -87,6 +89,8 @@ public class PromptInfo implements Parcelable { mIsForLegacyFingerprintManager = in.readBoolean(); mShowEmergencyCallButton = in.readBoolean(); mUseParentProfileForDeviceCredential = in.readBoolean(); + mComponentNameForConfirmDeviceCredentialActivity = in.readParcelable( + ComponentName.class.getClassLoader(), ComponentName.class); } public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() { @@ -132,10 +136,11 @@ public class PromptInfo implements Parcelable { dest.writeBoolean(mIsForLegacyFingerprintManager); dest.writeBoolean(mShowEmergencyCallButton); dest.writeBoolean(mUseParentProfileForDeviceCredential); + dest.writeParcelable(mComponentNameForConfirmDeviceCredentialActivity, 0); } // LINT.IfChange - public boolean containsTestConfigurations() { + public boolean requiresTestOrInternalPermission() { if (mIsForLegacyFingerprintManager && mAllowedSensorIds.size() == 1 && !mAllowBackgroundAuthentication) { @@ -148,11 +153,15 @@ public class PromptInfo implements Parcelable { return true; } else if (mIgnoreEnrollmentState) { return true; + } else if (mShowEmergencyCallButton) { + return true; + } else if (mComponentNameForConfirmDeviceCredentialActivity != null) { + return true; } return false; } - public boolean containsPrivateApiConfigurations() { + public boolean requiresInternalPermission() { if (mDisallowBiometricsIfPolicyExists) { return true; } else if (mUseDefaultTitle) { @@ -177,7 +186,7 @@ public class PromptInfo implements Parcelable { * Currently, logo res, logo bitmap, logo description, PromptContentViewWithMoreOptions needs * this permission. */ - public boolean containsAdvancedApiConfigurations() { + public boolean requiresAdvancedPermission() { if (mLogoRes != -1) { return true; } else if (mLogoBitmap != null) { @@ -305,6 +314,12 @@ public class PromptInfo implements Parcelable { mShowEmergencyCallButton = showEmergencyCallButton; } + public void setComponentNameForConfirmDeviceCredentialActivity( + ComponentName componentNameForConfirmDeviceCredentialActivity) { + mComponentNameForConfirmDeviceCredentialActivity = + componentNameForConfirmDeviceCredentialActivity; + } + public void setUseParentProfileForDeviceCredential( boolean useParentProfileForDeviceCredential) { mUseParentProfileForDeviceCredential = useParentProfileForDeviceCredential; @@ -417,6 +432,10 @@ public class PromptInfo implements Parcelable { return mShowEmergencyCallButton; } + public ComponentName getComponentNameForConfirmDeviceCredentialActivity() { + return mComponentNameForConfirmDeviceCredentialActivity; + } + private void checkOnlyOneLogoSet() { if (mLogoRes != -1 && mLogoBitmap != null) { throw new IllegalStateException( diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index a01961206319..2b7d8f155bff 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -838,7 +838,10 @@ public final class CameraManager { return new CameraExtensionCharacteristics(mContext, cameraId, characteristicsMap); } - private Map<String, CameraCharacteristics> getPhysicalIdToCharsMap( + /** + * @hide + */ + public Map<String, CameraCharacteristics> getPhysicalIdToCharsMap( CameraCharacteristics chars) throws CameraAccessException { HashMap<String, CameraCharacteristics> physicalIdsToChars = new HashMap<String, CameraCharacteristics>(); @@ -974,8 +977,6 @@ public final class CameraManager { final int oomScoreOffset, int rotationOverride) throws CameraAccessException { CameraCharacteristics characteristics = getCameraCharacteristics(cameraId); CameraDevice device = null; - Map<String, CameraCharacteristics> physicalIdsToChars = - getPhysicalIdToCharsMap(characteristics); synchronized (mLock) { ICameraDeviceUser cameraUser = null; CameraDevice.CameraDeviceSetup cameraDeviceSetup = null; @@ -990,7 +991,7 @@ public final class CameraManager { callback, executor, characteristics, - physicalIdsToChars, + this, mContext.getApplicationInfo().targetSdkVersion, mContext, cameraDeviceSetup); ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks(); diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 81bb9ac33df2..e2b409fe35f1 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -31,6 +31,7 @@ import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraExtensionCharacteristics; +import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CameraOfflineSession; import android.hardware.camera2.CaptureFailure; @@ -146,7 +147,8 @@ public class CameraDeviceImpl extends CameraDevice private final String mCameraId; private final CameraCharacteristics mCharacteristics; - private final Map<String, CameraCharacteristics> mPhysicalIdsToChars; + private Map<String, CameraCharacteristics> mPhysicalIdsToChars; + private final CameraManager mCameraManager; private final int mTotalPartialCount; private final Context mContext; @@ -341,11 +343,12 @@ public class CameraDeviceImpl extends CameraDevice public CameraDeviceImpl(String cameraId, StateCallback callback, Executor executor, CameraCharacteristics characteristics, - Map<String, CameraCharacteristics> physicalIdsToChars, + @NonNull CameraManager manager, int appTargetSdkVersion, Context ctx, @Nullable CameraDevice.CameraDeviceSetup cameraDeviceSetup) { - if (cameraId == null || callback == null || executor == null || characteristics == null) { + if (cameraId == null || callback == null || executor == null || characteristics == null + || manager == null) { throw new IllegalArgumentException("Null argument given"); } mCameraId = cameraId; @@ -357,7 +360,7 @@ public class CameraDeviceImpl extends CameraDevice mDeviceExecutor = executor; } mCharacteristics = characteristics; - mPhysicalIdsToChars = physicalIdsToChars; + mCameraManager = manager; mAppTargetSdkVersion = appTargetSdkVersion; mContext = ctx; mCameraDeviceSetup = cameraDeviceSetup; @@ -379,6 +382,18 @@ public class CameraDeviceImpl extends CameraDevice } } + private Map<String, CameraCharacteristics> getPhysicalIdToChars() { + if (mPhysicalIdsToChars == null) { + try { + mPhysicalIdsToChars = mCameraManager.getPhysicalIdToCharsMap(mCharacteristics); + } catch (CameraAccessException e) { + Log.e(TAG, "Unable to query the physical characteristics map!"); + } + } + + return mPhysicalIdsToChars; + } + public CameraDeviceCallbacks getCallbacks() { return mCallbacks; } @@ -1598,7 +1613,7 @@ public class CameraDeviceImpl extends CameraDevice return true; } - for (Map.Entry<String, CameraCharacteristics> entry : mPhysicalIdsToChars.entrySet()) { + for (Map.Entry<String, CameraCharacteristics> entry : getPhysicalIdToChars().entrySet()) { configMap = entry.getValue().get(ck); if (configMap != null && @@ -2621,7 +2636,7 @@ public class CameraDeviceImpl extends CameraDevice public void createExtensionSession(ExtensionSessionConfiguration extensionConfiguration) throws CameraAccessException { HashMap<String, CameraCharacteristics> characteristicsMap = new HashMap<>( - mPhysicalIdsToChars); + getPhysicalIdToChars()); characteristicsMap.put(mCameraId, mCharacteristics); boolean initializationFailed = true; IBinder token = new Binder(TAG + " : " + mNextSessionId++); diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java index d340f3ff70bb..3f2ef84a4ef0 100644 --- a/core/java/android/hardware/face/FaceManager.java +++ b/core/java/android/hardware/face/FaceManager.java @@ -732,6 +732,10 @@ public class FaceManager implements BiometricAuthenticator { /** * Get statically configured sensor properties. + * @deprecated Generally unsafe to use, use + * {@link FaceManager#addAuthenticatorsRegisteredCallback} API instead. + * In most cases this method will work as expected, but during early boot up, it will be + * null/empty and there is no way for the caller to know when it's actual value is ready. * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 25bfb2ab91e7..2ded615580fd 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -1189,6 +1189,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing /** * Get statically configured sensor properties. + * @deprecated Generally unsafe to use, use + * {@link FingerprintManager#addAuthenticatorsRegisteredCallback} API instead. + * In most cases this method will work as expected, but during early boot up, it will be + * null/empty and there is no way for the caller to know when it's actual value is ready. * @hide */ @RequiresPermission(USE_BIOMETRIC_INTERNAL) diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 0e285601b76f..2ca58d16eaae 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -166,6 +166,16 @@ flag { } flag { + name: "finish_running_ops_for_killed_packages" + namespace: "permissions" + description: "Finish all appops for a dead app process" + bug: "234630570" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "runtime_permission_appops_mapping_enabled" is_fixed_read_only: true namespace: "permissions" diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 5f6bdbf193b9..38ab590b3c46 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -18,7 +18,7 @@ package android.service.dreams; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.service.dreams.Flags.dreamHandlesConfirmKeys; -import static android.service.dreams.Flags.dreamTracksFocus; +import static android.service.dreams.Flags.dreamHandlesBeingObscured; import android.annotation.FlaggedApi; import android.annotation.IdRes; @@ -571,15 +571,6 @@ public class DreamService extends Service implements Window.Callback { /** {@inheritDoc} */ @Override public void onWindowFocusChanged(boolean hasFocus) { - if (!dreamTracksFocus()) { - return; - } - - try { - mDreamManager.onDreamFocusChanged(hasFocus); - } catch (RemoteException ex) { - // system server died - } } /** {@inheritDoc} */ @@ -1737,7 +1728,7 @@ public class DreamService extends Service implements Window.Callback { @Override public void comeToFront() { - if (!dreamTracksFocus()) { + if (!dreamHandlesBeingObscured()) { return; } diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl index 85f0368a7b5c..cf98bfe05faf 100644 --- a/core/java/android/service/dreams/IDreamManager.aidl +++ b/core/java/android/service/dreams/IDreamManager.aidl @@ -48,5 +48,6 @@ interface IDreamManager { void setSystemDreamComponent(in ComponentName componentName); void registerDreamOverlayService(in ComponentName componentName); void startDreamActivity(in Intent intent); - void onDreamFocusChanged(in boolean hasFocus); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)") + oneway void setDreamIsObscured(in boolean isObscured); } diff --git a/core/java/android/service/dreams/flags.aconfig b/core/java/android/service/dreams/flags.aconfig index a42eaff68917..54d950c18af8 100644 --- a/core/java/android/service/dreams/flags.aconfig +++ b/core/java/android/service/dreams/flags.aconfig @@ -39,8 +39,11 @@ flag { } flag { - name: "dream_tracks_focus" + name: "dream_handles_being_obscured" namespace: "communal" - description: "This flag enables the ability for dreams to track whether or not they have focus" - bug: "331798001" + description: "This flag enables the ability for dreams to handle being obscured" + bug: "337302237" + metadata { + purpose: PURPOSE_BUGFIX + } } diff --git a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java index 29a6db6a12a0..8237b20260ea 100644 --- a/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java +++ b/core/java/android/service/ondeviceintelligence/OnDeviceSandboxedInferenceService.java @@ -105,6 +105,21 @@ public abstract class OnDeviceSandboxedInferenceService extends Service { public static final String SERVICE_INTERFACE = "android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService"; + // TODO(339594686): make API + /** + * @hide + */ + public static final String REGISTER_MODEL_UPDATE_CALLBACK_BUNDLE_KEY = + "register_model_update_callback"; + /** + * @hide + */ + public static final String MODEL_LOADED_BUNDLE_KEY = "model_loaded"; + /** + * @hide + */ + public static final String MODEL_UNLOADED_BUNDLE_KEY = "model_unloaded"; + private IRemoteStorageService mRemoteStorageService; /** diff --git a/core/java/android/window/TransitionFilter.java b/core/java/android/window/TransitionFilter.java index 64fe66e36bc3..ec4e3e9163fa 100644 --- a/core/java/android/window/TransitionFilter.java +++ b/core/java/android/window/TransitionFilter.java @@ -25,6 +25,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.WindowConfiguration; import android.content.ComponentName; +import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.view.WindowManager; @@ -180,6 +181,7 @@ public final class TransitionFilter implements Parcelable { public @ContainerOrder int mOrder = CONTAINER_ORDER_ANY; public ComponentName mTopActivity; + public IBinder mLaunchCookie; public Requirement() { } @@ -193,6 +195,7 @@ public final class TransitionFilter implements Parcelable { mMustBeTask = in.readBoolean(); mOrder = in.readInt(); mTopActivity = in.readTypedObject(ComponentName.CREATOR); + mLaunchCookie = in.readStrongBinder(); } /** Go through changes and find if at-least one change matches this filter */ @@ -231,6 +234,9 @@ public final class TransitionFilter implements Parcelable { if (mMustBeTask && change.getTaskInfo() == null) { continue; } + if (!matchesCookie(change.getTaskInfo())) { + continue; + } return true; } return false; @@ -247,13 +253,25 @@ public final class TransitionFilter implements Parcelable { return false; } + private boolean matchesCookie(ActivityManager.RunningTaskInfo info) { + if (mLaunchCookie == null) return true; + if (info == null) return false; + for (IBinder cookie : info.launchCookies) { + if (mLaunchCookie.equals(cookie)) { + return true; + } + } + return false; + } + /** Check if the request matches this filter. It may generate false positives */ boolean matches(@NonNull TransitionRequestInfo request) { // Can't check modes/order since the transition hasn't been built at this point. if (mActivityType == ACTIVITY_TYPE_UNDEFINED) return true; return request.getTriggerTask() != null && request.getTriggerTask().getActivityType() == mActivityType - && matchesTopActivity(request.getTriggerTask(), null /* activityCmp */); + && matchesTopActivity(request.getTriggerTask(), null /* activityCmp */) + && matchesCookie(request.getTriggerTask()); } @Override @@ -267,6 +285,7 @@ public final class TransitionFilter implements Parcelable { dest.writeBoolean(mMustBeTask); dest.writeInt(mOrder); dest.writeTypedObject(mTopActivity, flags); + dest.writeStrongBinder(mLaunchCookie); } @NonNull @@ -307,6 +326,7 @@ public final class TransitionFilter implements Parcelable { out.append(" mustBeTask=" + mMustBeTask); out.append(" order=" + containerOrderToString(mOrder)); out.append(" topActivity=").append(mTopActivity); + out.append(" launchCookie=").append(mLaunchCookie); out.append("}"); return out.toString(); } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index f931a762871c..e29f256146d0 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -47,7 +47,7 @@ oneway interface IStatusBar void animateExpandNotificationsPanel(); void animateExpandSettingsPanel(String subPanel); void animateCollapsePanels(); - void togglePanel(); + void toggleNotificationsPanel(); void showWirelessChargingAnimation(int batteryLevel); diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index b83b2d20c561..fc60f065a965 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -17,7 +17,6 @@ package com.android.internal.statusbar; import android.app.Notification; -import android.app.StatusBarManager; import android.content.ComponentName; import android.graphics.drawable.Icon; import android.graphics.Rect; @@ -53,9 +52,9 @@ interface IStatusBarService void togglePanel(); @UnsupportedAppUsage void disable(int what, IBinder token, String pkg); + void disableForUser(int what, IBinder token, String pkg, int userId); void disable2(int what, IBinder token, String pkg); - void disableForUser(in StatusBarManager.DisableInfo info, IBinder token, String pkg, int userId, String reason); - + void disable2ForUser(int what, IBinder token, String pkg, int userId); int[] getDisableFlags(IBinder token, int userId); void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription); @UnsupportedAppUsage diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp index bf2fddab3d41..acef609448ad 100644 --- a/core/jni/platform/host/HostRuntime.cpp +++ b/core/jni/platform/host/HostRuntime.cpp @@ -330,7 +330,7 @@ static void init_keyboard(JNIEnv* env, const vector<string>& keyboardPaths) { InputDeviceInfo info = InputDeviceInfo(); info.initialize(keyboardId, 0, 0, InputDeviceIdentifier(), "keyboard " + std::to_string(keyboardId), true, false, - ui::ADISPLAY_ID_DEFAULT); + ui::LogicalDisplayId::DEFAULT); info.setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC); info.setKeyCharacterMap(*charMap); diff --git a/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml b/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml index 7c45c20a758b..c692967d36b3 100644 --- a/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml +++ b/core/res/res/drawable/ic_signal_cellular_1_4_bar.xml @@ -22,11 +22,11 @@ <path android:fillColor="@android:color/white" android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" /> - <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z"> + <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z"> <!-- 1 bar. move to higher ground. --> <path android:name="ic_signal_cellular_1_4_bar" android:fillColor="@android:color/white" - android:pathData="M6,0 H11 V20 H6 z" /> + android:pathData="M0,0 H11 V24 H0 z" /> </clip-path> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml index 02b646d310e5..b01c26972ac8 100644 --- a/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml +++ b/core/res/res/drawable/ic_signal_cellular_1_5_bar.xml @@ -22,11 +22,11 @@ <path android:fillColor="@android:color/white" android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" /> - <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z"> + <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z"> <!-- 1 bar. might have to call you back. --> <path android:name="ic_signal_cellular_1_5_bar" android:fillColor="@android:color/white" - android:pathData="M6,0 H12 V20 H6 z" /> + android:pathData="M0,0 H12 V24 H0 z" /> </clip-path> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml b/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml index 514d1690abcf..982623d41060 100644 --- a/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml +++ b/core/res/res/drawable/ic_signal_cellular_2_4_bar.xml @@ -22,11 +22,11 @@ <path android:fillColor="@android:color/white" android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" /> - <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z"> + <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z"> <!-- 2 bars. 2 out of 4 ain't bad. --> <path android:name="ic_signal_cellular_2_4_bar" android:fillColor="@android:color/white" - android:pathData="M6,0 H14 V20 H6 z" /> + android:pathData="M0,0 H14 V24 H0 z" /> </clip-path> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml index a97f771a6632..75daadd213dc 100644 --- a/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml +++ b/core/res/res/drawable/ic_signal_cellular_2_5_bar.xml @@ -23,11 +23,11 @@ <path android:fillColor="@android:color/white" android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" /> - <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z"> + <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z"> <!-- 2 bars. hanging in there. --> <path android:name="ic_signal_cellular_2_5_bar" android:fillColor="@android:color/white" - android:pathData="M6,0 H14 V20 H6 z" /> + android:pathData="M0,0 H14 V24 H0 z" /> </clip-path> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml b/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml index 1bacf4ad678f..4e4bea397d26 100644 --- a/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml +++ b/core/res/res/drawable/ic_signal_cellular_3_4_bar.xml @@ -22,11 +22,11 @@ <path android:fillColor="@android:color/white" android:pathData="M20,7v13H7L20,7 M22,2L2,22h20V2L22,2z" /> - <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z"> + <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z"> <!-- 3 bars. quite nice. --> <path android:name="ic_signal_cellular_3_4_bar" android:fillColor="@android:color/white" - android:pathData="M6,0 H17 V20 H6 z" /> + android:pathData="M0,0 H17 V24 H0 z" /> </clip-path> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml index 2789d3e9305c..9a98c2982574 100644 --- a/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml +++ b/core/res/res/drawable/ic_signal_cellular_3_5_bar.xml @@ -22,11 +22,11 @@ <path android:fillColor="@android:color/white" android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" /> - <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z"> + <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z"> <!-- 3 bars. not great, not terrible. --> <path android:name="ic_signal_cellular_3_5_bar" android:fillColor="@android:color/white" - android:pathData="M6,0 H16 V20 H6 z" /> + android:pathData="M0,0 H16 V24 H0 z" /> </clip-path> </vector>
\ No newline at end of file diff --git a/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml b/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml index 8286dbb5576f..2a37d011c650 100644 --- a/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml +++ b/core/res/res/drawable/ic_signal_cellular_4_5_bar.xml @@ -22,11 +22,11 @@ <path android:fillColor="@android:color/white" android:pathData="M20,7V20H7L20,7m2-5L2,22H22V2Z" /> - <clip-path android:name="triangle" android:pathData="M20,7v13H7L20,7z"> + <clip-path android:name="triangle" android:pathData="M21,5 V21 H5 z"> <!-- 4 bars. extremely respectable. --> <path android:name="ic_signal_cellular_4_5_bar" android:fillColor="@android:color/white" - android:pathData="M6,0 H18 V20 H6 z" /> + android:pathData="M0,0 H18 V24 H0 z" /> </clip-path> </vector>
\ No newline at end of file diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index b65fc5f4e890..2a3c691dcd04 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Maak Boodskappe oop"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Hoe dit werk"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Hangend …"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index cef77b026c83..08a290c454f3 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"መልዕክቶች ይክፈቱ"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"እንዴት እንደሚሠራ"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"በመጠባበቅ ላይ..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 2a5822a5fa1c..20d491fd22d8 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -165,8 +165,8 @@ <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"تم الاتصال بشبكة \"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>\" المشفَّرة"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"أصبح الاتصال باستخدام شريحة SIM لشبكة \"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>\" أكثر أمانًا الآن"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"تم الاتصال بشبكة غير مشفَّرة"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"المكالمات والرسائل والبيانات هي أكثر عرضة للاختراق في الوقت الحالي أثناء استخدام شريحة SIM لشبكة \"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>\""</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"المكالمات والرسائل والبيانات هي أكثر عرضة للاختراق في الوقت الحالي أثناء استخدام شريحة SIM لشبكة \"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>\".\n\nستتلقّى إشعارًا آخر عندما يتم تشفير اتصالك مرة أخرى."</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"تكون المكالمات والرسائل والبيانات في الوقت الحالي أكثر عرضة للاختراق أثناء استخدام شريحة SIM من شبكة \"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>\""</string> + <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"تكون المكالمات والرسائل والبيانات في الوقت الحالي أكثر عرضة للاختراق أثناء استخدام شريحة SIM من شبكة \"<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> @@ -849,7 +849,7 @@ <string name="policylab_forceLock" msgid="7360335502968476434">"قفل الشاشة"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"التحكّم في طريقة ووقت قفل الشاشة"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"محو جميع البيانات"</string> - <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"يمكنك محو بيانات الجهاز اللوحي بدون تحذير، وذلك عبر إجراء إعادة الضبط على الإعدادات الأصلية."</string> + <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"محو بيانات الجهاز اللوحي بدون تحذير، وذلك عبر إعادة الضبط على الإعدادات الأصلية"</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"يمكنك محو بيانات جهاز Android TV بدون تحذير عن طريق تنفيذ إعادة الضبط على الإعدادات الأصلية."</string> <string name="policydesc_wipeData" product="automotive" msgid="660804547737323300">"يمكنك محو بيانات \"نظام الترفيه والمعلومات\" بدون تحذير، وذلك من خلال إعادة الضبط على الإعدادات الأصلية."</string> <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"محو بيانات الهاتف بدون تحذير، وذلك من خلال إعادة ضبط البيانات على الإعدادات الأصلية"</string> @@ -2417,4 +2417,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"فتح تطبيق \"الرسائل\""</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"طريقة العمل"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"بانتظار الإزالة من الأرشيف…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index 6e0da5454350..30ced90bd5e4 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages খোলক"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ই কেনেকৈ কাম কৰে"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"বিবেচনাধীন হৈ আছে..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index a3d4423ea772..49073f11f897 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Mesajı açın"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Haqqında"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Gözləmədə..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index fff999ac57c4..ca66ef4a018f 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -161,7 +161,7 @@ <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Mreža u blizini je u <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> evidentirala jedinstveni ID vašeg uređaja (IMSI ili IMEI) dok ste koristili <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM.\n\nTo znači da je evidentirala vašu lokaciju, aktivnost i identitet. To je uobičajena praksa, ali može da bude problem ljudima koji su zabrinuti za privatnost."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Povezani ste na šifrovanu mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Veza <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM-a je sada bezbednija"</string> - <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Povezani ste na šifrovanu mrežu"</string> + <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Povezani ste na nešifrovanu mrežu"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Pozivi, poruke i podaci su trenutno ranjiviji dok koristite <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Pozivi, poruke i podaci su trenutno ranjiviji dok koristite <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM.\n\nKada veza ponovo bude šifrovana, poslaćemo vam drugo obaveštenje."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Podešavanja bezbednosti na mobilnoj mreži"</string> @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvori Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Princip rada"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Na čekanju..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 19ca1c4da054..4cd150a6ebf6 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -162,7 +162,7 @@ <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"У <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> у сетцы паблізу быў запісаны ўнікальны ідэнтыфікатар вашай прылады (IMSI або IMEI) пры выкарыстанні SIM-карты <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>.\n\nГэта азначае, што даныя пра ваша месцазнаходжанне, дзеянні або асобу былі зарэгістраваны. Гэта звычайная практыка, але можа быць праблемай для людзей, якія турбуюцца аб прыватнасці."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Падключана да зашыфраванай сеткі <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Цяпер падключэнне да SIM-карты <xliff:g id="NETWORK_NAME">%1$s</xliff:g> стала больш бяспечным"</string> - <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Падключана да зашыфраванай сеткі"</string> + <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Падключана да незашыфраванай сеткі"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Зараз выклікі, паведамленні і даныя менш абаронены пры выкарыстанні SIM-карты <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Зараз выклікі, паведамленні і даныя менш абаронены пры выкарыстанні SIM-карты <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nКалі падключэнне будзе зноў зашыфравана, вы атрымаеце апавяшчэнне."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Налады сеткавай бяспекі"</string> @@ -2415,4 +2415,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Адкрыць Паведамленні"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Як гэта працуе"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"У чаканні..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 2f1ecdbbbb91..eb2e9207367f 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -161,7 +161,7 @@ <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Установена е връзка с шифрованата мрежа <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Връзката със SIM картата от <xliff:g id="NETWORK_NAME">%1$s</xliff:g> вече е по-сигурна"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Установена е връзка с нешифрована мрежа"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Понастоящем обажданията, съобщенията и данните са по-уязвими, докато използвате SIM картата си от <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Обажданията, съобщенията и данните са по-уязвими, докато използвате SIM картата си от <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Понастоящем обажданията, съобщенията и данните са по-уязвими, докато използвате SIM картата си от <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nСлед като връзката ви бъде шифрована отново, ще получите друго известие."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Настройки за сигурност на мобилната мрежа"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Научете повече"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Отваряне на Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Начин на работа"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Изчаква..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index f1ebfb02faa5..6618127ada43 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -157,7 +157,7 @@ <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"এনক্রিপশন, এনক্রিপটেড নয় এমন নেটওয়ার্কের জন্য বিজ্ঞপ্তি"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"ডিভাইস আইডি অ্যাক্সেস করা হয়েছে"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"আপনার <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> সিম কার্ড ব্যবহার করে <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>-এ, আশেপাশের নেটওয়ার্ক আপনার ডিভাইসের অনন্য আইডি (IMSI অথবা IMEI) রেকর্ড করেছে"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"আপনার <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> সিম কার্ড ব্যবহার করে <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>-এ, আশেপাশের নেটওয়ার্ক আপনার ডিভাইসের অনন্য আইডি (IMSI অথবা IMEI) রেকর্ড করেছে।\n\nএটির মানে হল আপনার লোকেশন, অ্যাক্টিভিটি বা পরিচিতি লগ-ইন করা হয়েছে। এটি সাধারণ পদ্ধতি কিন্তু সেইসব লোকজনের জন্য সমস্যা হতে পারে যারা নিজেদের গোপনীয়তা নিয়ে উদ্বেগে থাকেন।"</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"আপনার <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> সিম কার্ড ব্যবহার করে <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>-এ, আশেপাশের নেটওয়ার্ক আপনার ডিভাইসের অনন্য আইডি (IMSI অথবা IMEI) রেকর্ড করেছে।\n\nএটির মানে হল আপনার লোকেশন, অ্যাক্টিভিটি বা পরিচিতি লগ করা হয়েছে। এটি সাধারণ পদ্ধতি কিন্তু সেইসব লোকজনের জন্য সমস্যা হতে পারে যারা নিজেদের গোপনীয়তা নিয়ে উদ্বেগে থাকেন।"</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> এনক্রিপটেড নেটওয়ার্কের সাথে কানেক্ট করা রয়েছে"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"এখন <xliff:g id="NETWORK_NAME">%1$s</xliff:g> সিম কার্ডের কানেকশন আরও সুরক্ষিত"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"এনক্রিপটেড নয় এমন নেটওয়ার্কের সাথে কানেক্ট করা রয়েছে"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages খুলুন"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"এটি কীভাবে কাজ করে"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"বাকি আছে…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index 1212af9c2a24..4f058bf74b41 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvorite Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kako ovo funkcionira"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Na čekanju…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index f2447791a65a..77fd6b833bb8 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Obre Missatges"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Com funciona"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendent..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 6b0426729a1d..5615f79d1013 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -2415,4 +2415,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otevřít Zprávy"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Jak to funguje"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Čeká na vyřízení…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 9bd374ae12e9..fd04e42c8e1f 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Åbn Beskeder"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Sådan fungerer det"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Afventer…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 24a71b5ca45d..630ec7512784 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -156,12 +156,12 @@ <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Sicherheit des Mobilfunknetzes"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Verschlüsselung, Benachrichtigungen für unverschlüsselte Netzwerke"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Auf Geräte-ID zugegriffen"</string> - <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Um <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> hat ein Netzwerk in der Nähe die eindeutige ID (IMSI oder IMEI) deines Geräts aufgezeichnet, während du deine <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>-SIM verwendet hast."</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Um <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> hat ein Netzwerk in der Nähe die eindeutige ID (IMSI oder IMEI) deines Geräts aufgezeichnet, während du deine <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>-SIM verwendet hast.\n\nDaher wurden dein Standort, deine Aktivitäten oder deine Identität protokolliert. Das ist zwar üblich, kann jedoch ein Problem für Personen sein, denen ihre Privatsphäre wichtig ist."</string> + <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Um <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> hat ein Netzwerk in der Nähe die eindeutige ID (IMSI oder IMEI) deines Geräts aufgezeichnet, während du <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>-SIM verwendet hast."</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Um <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> hat ein Netzwerk in der Nähe die eindeutige ID (IMSI oder IMEI) deines Geräts aufgezeichnet, während du <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>-SIM verwendet hast.\n\nDaher wurden dein Standort, deine Aktivitäten oder deine Identität protokolliert. Das ist zwar üblich, kann jedoch ein Problem für Personen sein, denen ihre Privatsphäre wichtig ist."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Mit verschlüsseltem Netzwerk „<xliff:g id="NETWORK_NAME">%1$s</xliff:g>“ verbunden"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Verbindung der <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-SIM ist jetzt sicherer"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Mit unverschlüsseltem Netzwerk verbunden"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Anrufe, Nachrichten und Daten sind momentan anfälliger für Angriffe, während du deine <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-SIM verwendest"</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Anrufe, Nachrichten und Daten sind anfälliger für Angriffe, während du <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-SIM verwendest"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Anrufe, Nachrichten und Daten sind momentan anfälliger für Angriffe, während du deine <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-SIM verwendest.\n\nWenn deine Verbindung wieder verschlüsselt ist, erhältst du eine weitere Benachrichtigung."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Einstellungen für die Sicherheit des Mobilfunknetzes"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Weitere Informationen"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages öffnen"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"So funktionierts"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Ausstehend…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 32611ef20d39..54901313dad2 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Άνοιγμα Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Πώς λειτουργεί"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Σε εκκρεμότητα…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index 1e1a6873ae4d..a32fcca8fc1f 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml index 9951afd5137f..9f06f71c147f 100644 --- a/core/res/res/values-en-rCA/strings.xml +++ b/core/res/res/values-en-rCA/strings.xml @@ -2413,4 +2413,13 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending..."</string> + <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string> + <string name="fingerprint_dangling_notification_msg_1" msgid="6261149111900787302">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted to improve performance"</string> + <string name="fingerprint_dangling_notification_msg_2" msgid="7688302770424064884">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted to improve performance"</string> + <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with fingerprint."</string> + <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted. Set them up again to unlock your phone with your fingerprint."</string> + <string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string> + <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Your face model wasn\'t working well and was deleted. Set it up again to unlock your phone with face."</string> + <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Set up"</string> + <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Not now"</string> </resources> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 8d5568169d33..bfcc4be89814 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index a8e397d5b054..80007323188c 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml index e7f713bb8822..0fe2cccd8d58 100644 --- a/core/res/res/values-en-rXC/strings.xml +++ b/core/res/res/values-en-rXC/strings.xml @@ -2413,4 +2413,13 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Open Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"How it works"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pending..."</string> + <string name="fingerprint_dangling_notification_title" msgid="7362075195588639989">"Set up Fingerprint Unlock again"</string> + <string name="fingerprint_dangling_notification_msg_1" msgid="6261149111900787302">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted to improve performance"</string> + <string name="fingerprint_dangling_notification_msg_2" msgid="7688302770424064884">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted to improve performance"</string> + <string name="fingerprint_dangling_notification_msg_all_deleted_1" msgid="2927018569542316055">"<xliff:g id="FINGERPRINT">%s</xliff:g> wasn\'t working well and was deleted. Set it up again to unlock your phone with fingerprint."</string> + <string name="fingerprint_dangling_notification_msg_all_deleted_2" msgid="6897989352716156176">"<xliff:g id="FINGERPRINT_0">%1$s</xliff:g> and <xliff:g id="FINGERPRINT_1">%2$s</xliff:g> weren\'t working well and were deleted. Set them up again to unlock your phone with your fingerprint."</string> + <string name="face_dangling_notification_title" msgid="947852541060975473">"Set up Face Unlock again"</string> + <string name="face_dangling_notification_msg" msgid="8806849376915541655">"Your face model wasn\'t working well and was deleted. Set it up again to unlock your phone with face."</string> + <string name="biometric_dangling_notification_action_set_up" msgid="8246885009807817961">"Set up"</string> + <string name="biometric_dangling_notification_action_not_now" msgid="8095249216864443491">"Not now"</string> </resources> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 5d4e95121033..8717640a6910 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -156,7 +156,7 @@ <string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string> <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Seguridad de redes móviles"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Encriptación, notificaciones para redes no encriptadas"</string> - <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Se accedió al ID de dispositivo"</string> + <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Se accedió al ID del dispositivo"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"A la(s) <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, una red cercana registró el ID único de tu dispositivo (IMSI o IMEI) mientras se usaba tu SIM de <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"A la(s) <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, una red cercana registró el ID único de tu dispositivo (IMSI o IMEI) mientras se usaba tu SIM de <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>.\n\nEsto significa que se registró tu ubicación, actividad o identidad. Esta es una práctica común, pero podría significar un problema para personas preocupadas por su privacidad."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Se conectó a la red encriptada de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir Mensajes"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cómo funciona"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendiente…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 19be81f0f4f9..6549da21376f 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -158,7 +158,7 @@ <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Cifrado, notificaciones sobre redes no cifradas"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Se ha accedido al ID del dispositivo"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"A las <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, una red cercana registró el ID único de tu dispositivo (IMSI o IMEI) mientras usabas la SIM de <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"A las <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, una red cercana registró el ID único de tu dispositivo (IMSI o IMEI) mientras usabas la SIM de <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>.\n\nEsto significa que se ha registrado tu ubicación, actividad o identidad. Se trata de una práctica habitual, pero puede ser un problema para aquellos a quienes les preocupa su privacidad."</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"A las <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, una red cercana registró el ID único de tu dispositivo (IMSI o IMEI) mientras usabas la SIM de <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>.\n\nEsto significa que se ha registrado tu ubicación, actividad o identidad. Se trata de una práctica habitual, pero puede ser un problema para quienes les preocupa su privacidad."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Conectado a la red cifrada <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Ahora, la conexión con la SIM de <xliff:g id="NETWORK_NAME">%1$s</xliff:g> es más segura"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Conectado a una red no cifrada"</string> @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abre Mensajes"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cómo funciona"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendiente..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 4a17e0db6c84..92f89e3ccb99 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -154,7 +154,7 @@ <string name="cfTemplateRegistered" msgid="5619930473441550596">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: pole suunatud"</string> <string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: pole edastatud"</string> <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Mobiilsidevõrgu turve"</string> - <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Krüpteerimine, märguanded krüpteerimata võrkude jaoks"</string> + <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Krüpteerimine, märguanded krüpteerimata võrkude kohta"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Seadme ID-le on juurde pääsetud"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Kell <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> salvestas lähedal olev võrk võrgu <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM-i kasutamise ajal teie seadme kordumatu ID (IMSI või IMEI)"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Kell <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> salvestas lähedal olev võrk võrgu <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM-i kasutamise ajal teie seadme kordumatu ID (IMSI või IMEI).\n\nSee tähendab, et teie asukoht, tegevus või isik salvestati. See on levinud tava, kuid võib osutada probleemiks inimeste jaoks, kellele on privaatsus eriti oluline."</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ava rakendus Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Tööpõhimõtted"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Ootel …"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 3f3404c56b8e..2d4130e23fc0 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -2144,10 +2144,8 @@ <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Ohitura moduaren informazio-jakinarazpena"</string> <string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Bateria-aurreztailea aktibatu da"</string> <string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Bateria-erabilera murrizten hasi da haren iraupena luzatzeko"</string> - <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) --> - <skip /> - <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) --> - <skip /> + <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Bateria-aurreztailea aktibatuta dago"</string> + <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Bateria-aurreztailea aktibatuta dago, bateriaren iraupena luzatzeko"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Bateria-aurreztailea"</string> <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Desaktibatu egin da bateria-aurreztailea"</string> <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Behar adina bateria dauka telefonoak. Jada ez dago eginbiderik murriztuta."</string> @@ -2415,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ireki Mezuak"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Nola funtzionatzen du?"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Zain…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index 3f850c12c9c2..07b267471157 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -155,12 +155,12 @@ <string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: هدایت نشده"</string> <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"امنیت شبکه تلفن همراه"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"رمزگذاری، اعلانهای شبکههای رمزگذارینشده"</string> - <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"شناسه دستگاه دردسترس قرار گرفته است"</string> + <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"شناسه دستگاه مورددسترس قرار گرفت"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"ساعت <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>، یکی از شبکههای اطراف شناسه یکتای دستگاهتان (IMSI یا IMEI) را هنگام استفاده از سیمکارت <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> ضبط کرده است"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"ساعت <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>، یکی از شبکههای اطراف شناسه یکتای دستگاهتان (IMSI یا IMEI) را هنگام استفاده از سیمکارت <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> ضبط کرده است.\n\nاین یعنی مکان، فعالیت، یا هویت شما ثبت شده است. این رویکرد عادی است اما ممکن است برای افرادی که نگران حریم خصوصیشان هستند مشکلساز باشد."</string> - <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"به شبکه رمزگذاریشده <xliff:g id="NETWORK_NAME">%1$s</xliff:g> متصل شدید"</string> + <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"به شبکه رمزگذاریشده <xliff:g id="NETWORK_NAME">%1$s</xliff:g> متصلاید"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"اتصال سیمکارت <xliff:g id="NETWORK_NAME">%1$s</xliff:g> اکنون ایمنتر است"</string> - <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"به شبکه رمزگذارینشده متصل شدید"</string> + <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"به شبکه رمزگذارینشده متصلاید"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"درحالحاضر تماسها، پیامها، و دادهها هنگام استفاده از سیمکارت <xliff:g id="NETWORK_NAME">%1$s</xliff:g> آسیبپذیرتر هستند"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"درحالحاضر تماسها، پیامها، و دادهها هنگام استفاده از سیمکارت <xliff:g id="NETWORK_NAME">%1$s</xliff:g> آسیبپذیرتر هستند.\n\nوقتی اتصال شما دوباره رمزگذاری شود، اعلان دیگری دریافت خواهید کرد."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"تنظیمات امنیت شبکه تلفن همراه"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"باز کردن «پیامها»"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"روش کار"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"درحال تعلیق…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 3e1adc44b0c3..e802443e5acb 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -160,7 +160,7 @@ <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Klo <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> lähellä oleva verkko tallensi laitteesi yksilöllisen tunnuksen (IMSI tai IMEI), kun käytössä oli SIM-kortti, jonka <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> tarjoaa.\n\nTämä tarkoittaa, että sijaintisi, toimintasi tai henkilöllisyytesi on tallennettu. Tämä on tavallista mutta voi huolestuttaa ihmisiä, jotka ovat tarkkoja yksityisyydestään."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Yhdistetty salattuun verkkoon <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"SIM-yhteys, jonka <xliff:g id="NETWORK_NAME">%1$s</xliff:g> tarjoaa, on nyt turvallisempi"</string> - <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Yhdistetty salattuun verkkoon"</string> + <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Yhdistetty salaamattomaan verkkoon"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Puhelut, viestit ja data ovat haavoittuvaisempia, kun käytössä on SIM-kortti, jonka <xliff:g id="NETWORK_NAME">%1$s</xliff:g> tarjoaa"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Puhelut, viestit ja data ovat haavoittuvaisempia, kun käytössä on SIM-kortti, jonka <xliff:g id="NETWORK_NAME">%1$s</xliff:g> tarjoaa.\n\nKun yhteys on taas salattu, saat uuden ilmoituksen."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Mobiiliverkkoa koskevat turvallisuusasetukset"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Avaa Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Näin se toimii"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Odottaa…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index dd968e1ec185..bf70c3cd4e97 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -162,8 +162,8 @@ <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Connecté à un réseau chiffré <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"La connexion à la carte SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> est maintenant plus sûre"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Connecté à un réseau non chiffré"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Les appels, les messages et les données sont actuellement plus vulnérables lorsque vous utilisez votre carte SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Les appels, les messages et les données sont actuellement plus vulnérables lorsque vous utilisez votre carte SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nUne fois que votre connexion est à nouveau chiffrée, vous recevez une nouvelle notification."</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Les appels, messages et données sont plus vulnérables lorsque vous utilisez votre carte SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> + <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Les appels, les messages et les données sont actuellement plus vulnérables lorsque vous utilisez votre carte SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nLorsque votre connexion sera à nouveau chiffrée, vous recevrez une nouvelle notification."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Paramètres de sécurité du réseau cellulaire"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"En savoir plus"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"OK"</string> @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ouvrir Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Fonctionnement"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"En attente…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 96636dcd3c60..57272245224f 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -163,7 +163,7 @@ <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"La connexion à la carte SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> est désormais plus sécurisée"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Connecté à un réseau non chiffré"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Les appels, les messages et les données sont actuellement plus vulnérables lorsque vous utilisez votre carte SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Les appels, les messages et les données sont actuellement plus vulnérables lorsque vous utilisez votre carte SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nLorsque votre connexion est à nouveau chiffrée, vous recevez une nouvelle notification."</string> + <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Les appels, les messages et les données sont actuellement plus vulnérables lorsque vous utilisez votre carte SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nLorsque votre connexion sera à nouveau chiffrée, vous recevrez une nouvelle notification."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Paramètres de sécurité du réseau mobile"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"En savoir plus"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"OK"</string> @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Ouvrir Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Fonctionnement"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"En attente…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 85ad42fe8ff5..663ef9ace52d 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -158,9 +158,9 @@ <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Acceso ao código do dispositivo"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Á/s <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, unha rede próxima rexistrou o código exclusivo (IMSI ou IMEI) do teu dispositivo mentres se usaba a túa SIM de <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Á/s <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, unha rede próxima rexistrou o código exclusivo (IMSI ou IMEI) do teu dispositivo mentres se usaba a túa SIM de <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>.\n\nIsto significa que se rexistrou a túa localización, actividade ou identidade. Aínda que se trata dunha práctica común, pode supoñer un problema para as persoas ás que lles preocupe a súa privacidade."</string> - <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Conexión á rede encriptada <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> + <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Conectácheste á rede encriptada <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"A conexión coa SIM de <xliff:g id="NETWORK_NAME">%1$s</xliff:g> agora é máis segura"</string> - <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Conexión a unha rede non encriptada"</string> + <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Conectácheste a unha rede non encriptada"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Cando usas a SIM de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>, as chamadas, mensaxes e datos son máis vulnerables"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Cando usas a SIM de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>, as chamadas, mensaxes e datos son máis vulnerables.\n\nRecibirás outra notificación cando se volva encriptar a túa conexión."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Configuración de seguranza das redes de telefonía móbil"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir Mensaxes"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona?"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 82ffb2f55c9d..dc4253750380 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ખોલો"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"તેની કામ કરવાની રીત"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"બાકી..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 8772cdc62a11..25f6ca1cc6f6 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -154,15 +154,15 @@ <string name="cfTemplateRegistered" msgid="5619930473441550596">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: अग्रेषित नहीं किया गया"</string> <string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: अग्रेषित नहीं किया गया"</string> <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"मोबाइल नेटवर्क की सुरक्षा"</string> - <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"उन नेटवर्क के लिए सुरक्षा से जुड़ी सूचनाएं जो सुरक्षित नहीं हैं"</string> + <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"एन्क्रिप्शन, असुरक्षित नेटवर्क के लिए सूचनाएं"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"डिवाइस आईडी को ऐक्सेस किया गया"</string> - <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"आपके <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> सिम का इस्तेमाल करके, आस-पास के नेटवर्क ने <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> आपके डिवाइस का यूनीक आईडी (IMSI या IMEI) रिकॉर्ड किया"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"आपका <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> सिम इस्तेमाल करके, आस-पास के नेटवर्क ने <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> आपके डिवाइस का यूनीक आईडी (IMSI या IMEI) रिकॉर्ड किया.\n\nइसका मतलब है कि आपकी जगह की जानकारी, गतिविधि या निजी जानकारी को लॉग इन किया गया है. यह सामान्य तरीका है. हालांकि, यह उन लोगों के लिए समस्या की वजह हो सकता है जिन्हें अपनी निजी जानकारी को लेकर चिंता रहती है."</string> + <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"आपके <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> सिम के ज़रिए, आस-पास के नेटवर्क ने <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> पर आपके डिवाइस का यूनीक आईडी (IMSI या IMEI) रिकॉर्ड किया"</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"आपके <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> सिम के ज़रिए, आस-पास के नेटवर्क ने <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> पर आपके डिवाइस का यूनीक आईडी (IMSI या IMEI) रिकॉर्ड किया.\n\nइसका मतलब है कि आपकी जगह की जानकारी, गतिविधि या निजी जानकारी को लॉग किया गया है. यह आम बात है. हालांकि, यह उन लोगों के लिए समस्या की वजह हो सकता है जिन्हें अपनी निजी जानकारी को लेकर चिंता रहती है."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"एन्क्रिप्ट यानी सुरक्षित नेटवर्क <xliff:g id="NETWORK_NAME">%1$s</xliff:g> से कनेक्ट किया गया"</string> - <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"अब <xliff:g id="NETWORK_NAME">%1$s</xliff:g> सिम का कनेक्शन ज़्यादा सुरक्षित है"</string> + <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"अब <xliff:g id="NETWORK_NAME">%1$s</xliff:g> सिम का कनेक्शन ज़्यादा सुरक्षित हो गया है"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"ऐसे नेटवर्क से कनेक्ट किया गया जो सुरक्षित नहीं है"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> सिम का इस्तेमाल करने के दौरान, कॉल, मैसेज, और डेटा को ऐक्सेस किए जाने का खतरा हो सकता है"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> सिम का इस्तेमाल करने के दौरान, कॉल, मैसेज, और डेटा को ऐक्सेस किए जाने का खतरा हो सकता है.\n\nजब आपका कनेक्शन फिर से एन्क्रिप्ट यानी सुरक्षित हो जाएगा, तब आपको दोबारा सूचना भेजी जाएगी."</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> सिम का इस्तेमाल करने पर, कॉल, मैसेज, और डेटा ऐक्सेस किए जाने का खतरा हो सकता है"</string> + <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> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ऐप्लिकेशन खोलें"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"यह सेटिंग कैसे काम करती है"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"प्रोसेस जारी है..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 88bc29fc3a3c..117d4e5632c6 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvori Poruke"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kako to funkcionira"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Na čekanju..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index f7e4a8f6ffe9..de8fa848edd6 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"A Messages megnyitása"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Hogyan működik?"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Függőben…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 251646c15031..d37993442bcf 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -153,9 +153,9 @@ <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> վայրկյանից"</string> <string name="cfTemplateRegistered" msgid="5619930473441550596">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. Չի վերահասցեավորվել"</string> <string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. Չի վերահասցեավորվել"</string> - <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Ցանցային անվտանգություն"</string> + <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Բջջային ցանցի անվտանգություն"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Գաղտնագրում, ծանուցումներ չգաղտնագրված ցանցերի համար"</string> - <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Սարքի նույնացույցիչը հասանելի է դարձել"</string> + <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Սարքի նույնացուցիչը հասանելի է դարձել"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Ժամը <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>-ին մոտակա ցանցը գրանցել է ձեր սարքի եզակի նույնացուցիչը (IMSI-ը կամ IMEI-ը) <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>-ի ձեր SIM քարտի օգտագործման ժամանակ"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Ժամը <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>-ին մոտակա ցանցը գրանցել է ձեր սարքի եզակի նույնացուցիչը (IMSI-ը կամ IMEI-ը) <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>-ի ձեր SIM քարտի օգտագործման ժամանակ։\n\nԴա նշանակում է, որ ձեր տեղադրությունը, գործողությունները կամ անձը նույնականացնող տվյալները գրանցվել են։ Սա սովորական գործելակերպ է, սակայն կարող է խնդիր լինել այն մարդկանց համար, որոնք մտահոգված են իրենց գաղտնիությամբ։"</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Հեռախոսը միացավ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> գաղտնագրված ցանցին"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Բացել Messages-ը"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ինչպես է դա աշխատում"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Առկախ է…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 139b4ab8338b..e6634d23fd62 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -157,12 +157,12 @@ <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Enkripsi, notifikasi untuk jaringan yang tidak terenkripsi"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"ID perangkat diakses"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Pada <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, jaringan di sekitar merekam ID unik perangkat Anda (IMSI atau IMEI) saat menggunakan kartu SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> Anda"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Pada <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, jaringan di sekitar merekam ID unik perangkat Anda (IMSI atau IMEI) saat menggunakan kartu SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> Anda.\n\nHal ini berarti lokasi, aktifitas, atau identitas Anda telah dicatat dalam log. Tindakan ini adalah praktik umum tetapi dapat menjadi masalah bagi orang yang mengkhawatirkan privasi."</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Pada <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, jaringan di sekitar merekam ID unik perangkat Anda (IMSI atau IMEI) saat menggunakan kartu SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> Anda.\n\nHal ini berarti lokasi, aktivitas, atau identitas Anda telah dicatat dalam log. Tindakan ini adalah praktik umum tetapi dapat menjadi masalah bagi orang yang mengkhawatirkan privasi."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Terhubung ke jaringan yang terenkripsi <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Koneksi kartu SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> kini lebih aman"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Terhubung ke jaringan yang tidak terenkripsi"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Panggilan, pesan, dan data saat ini lebih rentan saat menggunakan kartu SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> Anda"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Panggilan, pesan, dan data saat ini lebih rentan saat menggunakan kartu SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> Anda.\n\nKetika koneksi Anda terenkripsi lagi, Anda akan menerima notifikasi lainnya."</string> + <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Panggilan, pesan, dan data saat ini lebih rentan saat menggunakan kartu SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> Anda.\n\nKetika koneksi Anda terenkripsi lagi, Anda akan kembali menerima notifikasi."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Setelan keamanan jaringan seluler"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Pelajari lebih lanjut"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"Oke"</string> @@ -639,7 +639,7 @@ <string name="permdesc_mediaLocation" msgid="597912899423578138">"Mengizinkan aplikasi untuk membaca lokasi dari koleksi media Anda."</string> <string name="biometric_app_setting_name" msgid="3339209978734534457">"Gunakan biometrik"</string> <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Gunakan biometrik atau kunci layar"</string> - <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifikasi bahwa ini memang Anda"</string> + <string name="biometric_dialog_default_title" msgid="55026799173208210">"Verifikasi diri Anda"</string> <string name="biometric_dialog_default_subtitle" msgid="8457232339298571992">"Gunakan biometrik untuk melanjutkan"</string> <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"Gunakan biometrik atau kunci layar untuk melanjutkan"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"Hardware biometrik tidak tersedia"</string> @@ -2221,7 +2221,7 @@ <string name="miniresolver_call_information" msgid="6739417525304184083">"Organisasi Anda hanya mengizinkan menelepon dari aplikasi kerja"</string> <string name="miniresolver_sms_information" msgid="4311292661329483088">"Organisasi Anda hanya mengizinkan pengiriman pesan dari aplikasi kerja"</string> <string name="miniresolver_private_space_phone_information" msgid="4469511223312488570">"Anda hanya dapat melakukan panggilan telepon dari aplikasi Telepon pribadi. Panggilan yang dilakukan dengan aplikasi Telepon pribadi akan ditambahkan ke histori panggilan pribadi."</string> - <string name="miniresolver_private_space_messages_information" msgid="111285656327622118">"Anda hanya dapat mengirim pesan SMS dari aplikasi Message pribadi."</string> + <string name="miniresolver_private_space_messages_information" msgid="111285656327622118">"Anda hanya dapat mengirim pesan SMS dari aplikasi Pesan pribadi."</string> <string name="miniresolver_use_personal_browser" msgid="776072682871133308">"Gunakan browser pribadi"</string> <string name="miniresolver_use_work_browser" msgid="543575306251952994">"Gunakan browser kerja"</string> <string name="miniresolver_call" msgid="6386870060423480765">"Telepon"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Buka Message"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cara kerjanya"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Tertunda..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 1f55241f1363..f77a18a3911b 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Opna Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Svona virkar þetta"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Í bið…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 2f066b5f46cb..95ccad54d63f 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Apri Messaggi"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Come funziona"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"In attesa…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 3fc962acc9a7..fee437af96cf 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -162,9 +162,9 @@ <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"יש חיבור לרשת המוצפנת <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"החיבור של כרטיס ה-SIM של <xliff:g id="NETWORK_NAME">%1$s</xliff:g> מאובטח יותר עכשיו"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"יש חיבור לרשת לא מוצפנת"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"השיחות, ההודעות והנתונים שלך פגיעים יותר עכשיו בזמן השימוש בכרטיס ה-SIM של <xliff:g id="NETWORK_NAME">%1$s</xliff:g> שלך"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"שיחות, הודעות ונתונים פגיעים יותר עכשיו בזמן השימוש בכרטיס ה-SIM של <xliff:g id="NETWORK_NAME">%1$s</xliff:g> שלך.\n\nכשהחיבור שלך יוצפן שוב, תישלח אליך התראה נוספת."</string> - <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"הגדרות אבטחה של רשת סלולרית"</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"השיחות, ההודעות והנתונים שלך פגיעים יותר עכשיו בזמן השימוש בכרטיס ה-SIM של <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> + <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"השיחות, ההודעות והנתונים שלך פגיעים יותר עכשיו בזמן השימוש בכרטיס ה-SIM של <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="fcComplete" msgid="1080909484660507044">"קוד תכונה הושלם."</string> @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"לפתיחת Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"איך זה עובד"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"בהמתנה..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index db3ba5a49246..726db1c4ea89 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -154,7 +154,7 @@ <string name="cfTemplateRegistered" msgid="5619930473441550596">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string> <string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string> <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"モバイル ネットワーク セキュリティ"</string> - <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"暗号化(ネットワークが暗号化されていない場合に通知)"</string> + <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"暗号化、暗号化されていないネットワークに関する通知"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"デバイス ID へのアクセスが発生しました"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>、<xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> の SIM の使用中に付近のネットワークでお使いのデバイスの一意の ID(IMSI または IMEI)が記録されました"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>、<xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> の SIM の使用中に付近のネットワークでお使いのデバイスの一意の ID(IMSI または IMEI)が記録されました。\n\nつまり、あなたの位置情報、アクティビティ、身元などが記録されことになります。これはよくある事象ですが、プライバシーに不安を持たれている人にとっては問題になる可能性があります。"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"メッセージ アプリを開く"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"仕組み"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"保留中..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml index 97003c4fd11b..bdf6c489326b 100644 --- a/core/res/res/values-ka/strings.xml +++ b/core/res/res/values-ka/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages-ის გახსნა"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"მუშაობის პრინციპი"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"მომლოდინე..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index 116166d5c3c9..55cf92bb3280 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -162,7 +162,7 @@ <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Енді <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM картасымен қосылу қорғалған."</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Шифрланбаған желіге қосылды"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM картасын пайдаланған кезде, қазіргі уақытта қоңырауларға, хабарларға және деректерге қауіп төнеді."</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM картасын пайдаланған кезде, қазіргі уақытта қоңырауларға, хабарларға және деректерге қауіп төнеді.\n\nБайланыс қайта шифрланғанда, тағы бір хабарландыру келеді."</string> + <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM картасын пайдаланған кезде, қазір қоңырауларға, хабарларға және деректерге зиян тию қаупі жоғары.\n\nБайланыс қайта шифрланғанда, тағы бір хабарландыру келеді."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Мобильдік желінің қауіпсіздік параметрлері"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Толық ақпарат"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"Түсінікті"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages қолданбасын ашу"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Бұл қалай орындалады?"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Дайын емес…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 456256c1432c..6a826db47006 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -156,8 +156,8 @@ <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"សុវត្ថិភាពបណ្ដាញទូរសព្ទចល័ត"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"ការអ៊ីនគ្រីប ការជូនដំណឹងសម្រាប់បណ្ដាញដែលមិនបានអ៊ីនគ្រីប"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"បានចូលប្រើប្រាស់លេខសម្គាល់ឧបករណ៍"</string> - <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"នៅម៉ោង <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> បណ្ដាញនៅជិតបានកត់ត្រាលេខសម្គាល់ពិសេស (IMSI ឬ IMEI) របស់ឧបករណ៍អ្នក ពេលកំពុងប្រើស៊ីម <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> របស់អ្នក"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"នៅម៉ោង <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> បណ្ដាញនៅជិតបានកត់ត្រាលេខសម្គាល់ពិសេស (IMSI ឬ IMEI) របស់ឧបករណ៍អ្នក ពេលកំពុងប្រើស៊ីម <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> របស់អ្នក។\n\nនេះមានន័យថា ទីតាំង សកម្មភាព ឬអត្តសញ្ញាណរបស់អ្នកត្រូវបានចុះកំណត់ហេតុ។ នេះគឺជាការអនុវត្តទូទៅ ប៉ុន្តែអាចនឹងមានបញ្ហាសម្រាប់អ្នកដែលមានកង្វល់ពាក់ព័ន្ធនឹងឯកជនភាព។"</string> + <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"នៅម៉ោង <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> បណ្ដាញនៅជិតបានកត់ត្រាលេខកូដសម្គាល់ខុសពីគេ (IMSI ឬ IMEI) របស់ឧបករណ៍អ្នក ពេលកំពុងប្រើស៊ីម <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> របស់អ្នក"</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"នៅម៉ោង <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> បណ្ដាញនៅជិតបានកត់ត្រាលេខកូដសម្គាល់ខុសពីគេ (IMSI ឬ IMEI) របស់ឧបករណ៍អ្នក ពេលកំពុងប្រើស៊ីម <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> របស់អ្នក។\n\nនេះមានន័យថា ទីតាំង សកម្មភាព ឬអត្តសញ្ញាណរបស់អ្នកត្រូវបានកត់ត្រាទុក។ នេះគឺជាការអនុវត្តទូទៅ ប៉ុន្តែអាចនឹងមានបញ្ហាសម្រាប់អ្នកដែលមានកង្វល់ពាក់ព័ន្ធនឹងឯកជនភាព។"</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"បានភ្ជាប់ទៅបណ្ដាញដែលបានអ៊ីនគ្រីប <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"ការតភ្ជាប់ស៊ីម <xliff:g id="NETWORK_NAME">%1$s</xliff:g> កាន់តែមានសុវត្ថិភាពឥឡូវនេះ"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"បានភ្ជាប់ទៅបណ្ដាញដែលមិនបានអ៊ីនគ្រីប"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"បើកកម្មវិធី Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"របៀបដែលវាដំណើរការ"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"កំពុងរង់ចាំ..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 97f013638877..40d513893dda 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -156,12 +156,12 @@ <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ ಸೆಕ್ಯೂರಿಟಿ"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"ಎನ್ಕ್ರಿಪ್ಶನ್, ಎನ್ಕ್ರಿಪ್ಟ್ ಮಾಡದ ನೆಟ್ವರ್ಕ್ಗಳಿಗೆ ನೋಟಿಫಿಕೇಶನ್ಗಳು"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"ಸಾಧನದ ID ಅನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲಾಗಿದೆ"</string> - <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> ಸಮಯದಲ್ಲಿ, ನಿಮ್ಮ ಸಾಧನದ ಅನನ್ಯ ID (IMSI ಅಥವಾ IMEI) ಅನ್ನು ನಿಮ್ಮ <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM ಕಾರ್ಡ್ ಬಳಸುವಾಗ ಹತ್ತಿರದ ನೆಟ್ವರ್ಕ್ನಿಂದ ರೆಕಾರ್ಡ್ ಮಾಡಲಾಗಿದೆ"</string> + <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>ಕ್ಕೆ, <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM ಬಳಸುವಾಗ ಸಾಧನದ ಅನನ್ಯ ID (IMSI ಅಥವಾ IMEI)ಯನ್ನು ಹತ್ತಿರದ ನೆಟ್ವರ್ಕ್ ರೆಕಾರ್ಡ್ ಮಾಡಿದೆ"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> ಸಮಯದಲ್ಲಿ, ನಿಮ್ಮ ಸಾಧನದ ಅನನ್ಯ ID (IMSI ಅಥವಾ IMEI) ಅನ್ನು ನಿಮ್ಮ <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM ಕಾರ್ಡ್ ಬಳಸುವಾಗ ಹತ್ತಿರದ ನೆಟ್ವರ್ಕ್ನಿಂದ ರೆಕಾರ್ಡ್ ಮಾಡಲಾಗಿದೆ.\n\nಇದರರ್ಥ ನಿಮ್ಮ ಸ್ಥಳ, ಚಟುವಟಿಕೆ ಅಥವಾ ಗುರುತನ್ನು ಲಾಗ್ ಮಾಡಲಾಗಿದೆ. ಇದು ಸಾಮಾನ್ಯ ವಿಧಾನವಾಗಿದೆ ಆದರೆ ಗೌಪ್ಯತೆಯ ಕುರಿತು ಕಾಳಜಿವಹಿಸುವವರಿಗೆ ಸಮಸ್ಯೆಯಾಗಬಹುದು."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"ಎನ್ಕ್ರಿಪ್ಟ್ ಮಾಡಿದ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ನೆಟ್ವರ್ಕ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM ಕನೆಕ್ಷನ್ ಈಗ ಹೆಚ್ಚು ಸುರಕ್ಷಿತವಾಗಿದೆ"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"ಎನ್ಕ್ರಿಪ್ಟ್ ಮಾಡದ ನೆಟ್ವರ್ಕ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"ನಿಮ್ಮ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM ಕಾರ್ಡ್ ಬಳಸುವಾಗ ಕರೆಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಡೇಟಾ ಪ್ರಸ್ತುತ ಹೆಚ್ಚು ಸೂಕ್ಷ್ಮವಾಗಿರುತ್ತದೆ."</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"ನಿಮ್ಮ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM ಕಾರ್ಡ್ ಬಳಸುವಾಗ ಕರೆಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಬೇರೆಯವರು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಬಹುದಾದ ಅಪಾಯವಿರುತ್ತದೆ"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"ನಿಮ್ಮ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM ಕಾರ್ಡ್ ಬಳಸುವಾಗ ಕರೆಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಡೇಟಾ ಪ್ರಸ್ತುತ ಹೆಚ್ಚು ಸೂಕ್ಷ್ಮವಾಗಿರುತ್ತದೆ.\n\nನಿಮ್ಮ ಕನೆಕ್ಷನ್ ಅನ್ನು ಮತ್ತೆ ಎನ್ಕ್ರಿಪ್ಟ್ ಮಾಡಿದಾಗ, ನೀವು ಇನ್ನೊಂದು ನೋಟಿಫಿಕೇಶನ್ ಅನ್ನು ಪಡೆಯುತ್ತೀರಿ."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ ಸೆಕ್ಯೂರಿಟಿ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ಅನ್ನು ತೆರೆಯಿರಿ"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ಇದು ಹೇಗೆ ಕೆಲಸ ಮಾಡುತ್ತದೆ"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"ಬಾಕಿ ಉಳಿದಿದೆ..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index df29128d17ed..dd476281eec9 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"메시지 열기"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"작동 방식"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"대기 중…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 9511db4fd9d3..bb29c36a0410 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -156,13 +156,13 @@ <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Мобилдик тармактын коопсуздугу"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Шифрлөө, шифрленбеген тармактар жөнүндө билдирмелер"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Түзмөктүн идентификатору колдонулду"</string> - <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM картасын колдонуп жатканда жакын жердеги тармакта түзмөгүңүздүн өзгөчө идентификатору (IMSI же IMEI) жазылды"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM картасын колдонуп жатканда жакын жердеги тармакта түзмөгүңүздүн өзгөчө идентификатору (IMSI же IMEI) жазылды.\n\nЖүргөн жериңиз, аракеттериңиз же өздүгүңүз тууралуу маалымат катталды. Бул адаттагы көрүнүш болсо да, купуялыгы жөнүндө тынчсызданган адамдарга маселе жаратышы мүмкүн."</string> - <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Шифрленген тармакка (<xliff:g id="NETWORK_NAME">%1$s</xliff:g>) туташты"</string> + <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Саат <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM картасы колдонулуп жатканда, жакын жердеги тармак түзмөгүңүздүн өзгөчө идентификаторун (IMSI же IMEI) жазып алды."</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Саат <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM картасы колдонулуп жатканда, жакын жердеги тармак түзмөгүңүздүн өзгөчө идентификаторун (IMSI же IMEI) жазып алды.\n\nТактап айтканда, жүргөн жериңиз, аракеттериңиз же өздүгүңүз катталды. Бул адаттагы көрүнүш болсо да, купуялыгы жөнүндө тынчсызданган адамдарга маселе жаратышы мүмкүн."</string> + <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Шифрленген <xliff:g id="NETWORK_NAME">%1$s</xliff:g> тармагына туташты"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Эми <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM картасы менен туташуу коопсуз болуп калды"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Шифрленбеген тармакка туташты"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Учурда <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM картасын колдонсоңуз, чалууларга, билдирүүлөргө жана маалыматтарга коркунуч жаралышы мүмкүн"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Учурда <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM картасын колдонсоңуз, чалууларга, билдирүүлөргө жана маалыматтарга коркунуч жаралышы мүмкүн.\n\nТуташууңуз кайра шифрленгенде дагы бир билдирме аласыз."</string> + <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Учурда <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM картасын колдонсоңуз, чалууларга, билдирүүлөргө жана маалыматтарга коркунуч жаралышы мүмкүн.\n\nБайланышыңыз кайра шифрленгенде дагы бир билдирме аласыз."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Мобилдик тармактын коопсуздук параметрлери"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Кеңири маалымат"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"Түшүндүм"</string> @@ -1334,7 +1334,7 @@ <!-- no translation found for network_available_sign_in_detailed (7520423801613396556) --> <skip /> <string name="wifi_no_internet" msgid="1386911698276448061">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> Интернетке туташуусу жок"</string> - <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Параметрлерди ачуу үчүн таптап коюңуз"</string> + <string name="wifi_no_internet_detailed" msgid="634938444133558942">"Параметрлерди ачуу үчүн тийип коюңуз"</string> <string name="mobile_no_internet" msgid="4014455157529909781">"Мобилдик Интернет жок"</string> <string name="other_networks_no_internet" msgid="6698711684200067033">"Тармактын Интернет жок"</string> <string name="private_dns_broken_detailed" msgid="3709388271074611847">"Жеке DNS сервери жеткиликсиз"</string> @@ -1396,7 +1396,7 @@ <string name="usb_midi_notification_title" msgid="7404506788950595557">"USB аркылуу MIDI режими күйгүзүлдү"</string> <string name="usb_uvc_notification_title" msgid="2030032862673400008">"Түзмөк веб-камера катары туташты"</string> <string name="usb_accessory_notification_title" msgid="1385394660861956980">"USB шайманы туташты"</string> - <string name="usb_notification_message" msgid="4715163067192110676">"Кошумча параметрлерди ачуу үчүн таптап коюңуз."</string> + <string name="usb_notification_message" msgid="4715163067192110676">"Кошумча параметрлерди ачуу үчүн тийип коюңуз."</string> <string name="usb_power_notification_message" msgid="7284765627437897702">"Туташкан түзмөк кубатталууда. Дагы параметрлерди көрүү үчүн таптап коюңуз."</string> <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Аналогдук аудио жабдуу табылды"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Тиркелген түзмөк бул телефонго шайкеш келбейт. Көбүрөөк маалымат алуу үчүн таптап коюңуз."</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Жазышуулар колдонмосун ачуу"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ал кантип иштейт"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Кезекте турат..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index a0aded4e183d..5fa0fc135612 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"ເປີດ Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ມັນເຮັດວຽກແນວໃດ"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"ລໍຖ້າດຳເນີນການ..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 837bff76ecf2..e06c2efe31b8 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -2415,4 +2415,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Atidaryti programą „Messages“"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kaip tai veikia"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Laukiama..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 4e244734f340..d2a6cd9af5a6 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Atvērt lietotni Ziņojumi"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Darbības principi"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Gaida…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 3790be062ec2..796f9efe1bbc 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -153,7 +153,7 @@ <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> по <xliff:g id="TIME_DELAY">{2}</xliff:g> секунди"</string> <string name="cfTemplateRegistered" msgid="5619930473441550596">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не е препратено"</string> <string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не е проследен"</string> - <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Обезбедување на мобилна мрежа"</string> + <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Безбедност на мобилна мрежа"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Шифрирање, известувања за нешифрирани мрежи"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Пристапено е до ID на уредот"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Во <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, мрежа во близина го сними уникатниот ID (IMSI или IMEI) на вашиот телефон со користење на вашата SIM-картичка на <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>"</string> @@ -161,9 +161,9 @@ <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Поврзано со шифрирана мрежа <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Врската со SIM-картичката на <xliff:g id="NETWORK_NAME">%1$s</xliff:g> сега е побезбедна"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Поврзано со нешифрирана мрежа"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Повиците, пораките и податоците во моментов се почувствителни додека ја користите вашата SIM-картичка на <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Повиците, пораките и податоците се почувствителни кога го користите вашиот SIM од <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Повиците, пораките и податоците во моментов се почувствителни додека ја користите вашата SIM-картичка на <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nКога вашата врска ќе биде шифрирана повторно, ќе добиете уште едно известување."</string> - <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Поставки за обезбедување на мобилна мрежа"</string> + <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Поставки за безбедност на мобилната мрежа"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Дознајте повеќе"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"Сфатив"</string> <string name="fcComplete" msgid="1080909484660507044">"Кодот за карактеристиката заврши."</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Отворете ја Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Дознајте како функционира"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Во фаза на чекање…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index 563efdb47efd..a0b4c8d80e96 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages തുറക്കുക"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ഇത് പ്രവർത്തിക്കുന്നത് എങ്ങനെയാണ്"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"തീർപ്പാക്കിയിട്ടില്ല..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index afde064d48f9..5ba16fe87ffd 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1762,7 +1762,7 @@ <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> - <string name="owner_name" msgid="8713560351570795743">"Эзэмшигч"</string> + <string name="owner_name" msgid="8713560351570795743">"Өмчлөгч"</string> <string name="guest_name" msgid="8502103277839834324">"Зочин"</string> <string name="error_message_title" msgid="4082495589294631966">"Алдаа"</string> <string name="error_message_change_not_allowed" msgid="843159705042381454">"Энэ өөрчлөлтийг админ зөвшөөрөөгүй байна"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Мессежийг нээх"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Энэ хэрхэн ажилладаг вэ?"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Хүлээгдэж буй..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 8e8d354a3a5b..6c19cc592880 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages उघडा"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ते कसे काम करते"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"प्रलंबित आहे..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index fe4ab56b7975..82c1a5974c62 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -157,7 +157,7 @@ <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Penyulitan, pemberitahuan untuk rangkaian yang tidak disulitkan"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"ID peranti diakses"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Pada <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, rangkaian berdekatan merekodkan ID unik peranti anda (IMSI atau IMEI) semasa menggunakan SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> anda"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Pada <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, rangkaian berdekatan merekodkan ID unik peranti anda (IMSI atau IMEI) semasa menggunakan SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> anda.\n\nHal ini bermaksud bahawa lokasi, aktiviti atau identiti anda telah dilog. Amalan ini biasa dilakukan tetapi mungkin sukar dilakukan oleh pengguna yang bimbang tentang privasi."</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Pada <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, rangkaian berdekatan merekodkan ID unik peranti anda (IMSI atau IMEI) semasa menggunakan SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> anda.\n\nHal ini bermaksud bahawa lokasi, aktiviti atau identiti anda telah dilog. Amalan ini biasa dilakukan tetapi mungkin menjadi hal kepada pengguna yang bimbang tentang privasi."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Disambungkan kepada rangkaian <xliff:g id="NETWORK_NAME">%1$s</xliff:g> yang disulitkan"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Sambungan SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> kini lebih selamat"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Disambungkan kepada rangkaian yang tidak disulitkan"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Buka Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cara ciri ini berfungsi"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Belum selesai..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 5f5b0ab61661..43b7ffafd093 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -157,12 +157,12 @@ <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"အသွင်ဝှက်ခြင်း၊ အသွင်ဝှက်မထားသော ကွန်ရက်များအတွက် အကြောင်းကြားချက်များ"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"စက် ID သုံးထားသည်"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> တွင် သင့် <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> ဆင်းမ်ကတ်ကို သုံးနေစဉ် အနီးရှိ ကွန်ရက်သည် စက်ပစ္စည်း၏ သီးသန့် ID (IMSI (သို့) IMEI) ကို မှတ်တမ်းတင်ထားသည်"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> တွင် သင့် <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> ဆင်းမ်ကတ်ကို သုံးနေစဉ် အနီးရှိ ကွန်ရက်သည် စက်ပစ္စည်း၏ သီးသန့် ID (IMSI (သို့) IMEI) ကို မှတ်တမ်းတင်ထားသည်။\n\nဆိုလိုသည်မှာ သင့်တည်နေရာ၊ လုပ်ဆောင်ချက် (သို့) အထောက်အထားကို မှတ်တမ်းတင်ထားသည်။ ၎င်းသည် သာမန်လုပ်ဆောင်မှုဖြစ်သော်လည်း ကိုယ်ရေးအချက်အလက်လုံခြုံမှုနှင့်ပတ်သက်၍ စိုးရိမ်သောသူများအတွက် ပြဿနာတစ်ခု ဖြစ်နိုင်သည်။"</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> တွင် သင့် <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> ဆင်းမ်ကတ်ကို သုံးနေစဉ် အနီးရှိ ကွန်ရက်သည် စက်ပစ္စည်း၏ သီးသန့် ID (IMSI (သို့) IMEI) ကို မှတ်တမ်းတင်ထားသည်။\n\nဆိုလိုသည်မှာ သင့်တည်နေရာ၊ လုပ်ဆောင်ချက် (သို့) အထောက်အထားကို မှတ်တမ်းတင်ထားသည်။ ၎င်းသည် သာမန်လုပ်ဆောင်မှုဖြစ်သော်လည်း ကိုယ်ရေးအချက်အလက်လုံခြုံမှုနှင့် ပတ်သက်၍ အချို့သူများအတွက် စိုးရိမ်စရာ ဖြစ်နိုင်သည်။"</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"အသွင်ဝှက်ထားသော ကွန်ရက် <xliff:g id="NETWORK_NAME">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည်"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ဆင်းမ်ကတ် ချိတ်ဆက်မှုသည် ယခု ပိုမိုလုံခြုံပါပြီ"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"အသွင်ဝှက်မထားသော ကွန်ရက်သို့ ချိတ်ဆက်ထားသည်"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"သင့် <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ဆင်းမ်ကတ်ကို သုံးနေစဉ် ဖုန်းခေါ်ဆိုမှု၊ မက်ဆေ့ဂျ်နှင့် ဒေတာများသည် လက်ရှိတွင် ပိုမိုထိခိုက်လွယ်သည်"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"သင့် <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ဆင်းမ်ကတ်ကို သုံးနေစဉ် ဖုန်းခေါ်ဆိုမှု၊ မက်ဆေ့ဂျ်နှင့် ဒေတာများသည် လက်ရှိတွင် ပိုမိုထိခိုက်လွယ်သည်။\n\nသင့်ချိတ်ဆက်မှုကို ထပ်မံအသွင်ဝှက်လိုက်သောအခါ အကြောင်းကြားချက်နောက်တစ်ခု ရရှိပါမည်။"</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"သင့် <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ဆင်းမ် သုံးချိန်တွင် ဖုန်း၊ မက်ဆေ့ဂျ်၊ ဒေတာ လုံခြုံမှုအားနည်းသည်"</string> + <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> @@ -644,7 +644,7 @@ <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"ရှေ့ဆက်ရန် သင်၏ ဇီဝမက်ထရစ်အချက်အလက် (သို့) ဖန်သားပြင်လော့ခ်ကို သုံးပါ"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"ဇီဝအချက်အလက်သုံး ကွန်ပျူတာစက်ပစ္စည်း မရရှိနိုင်ပါ"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</string> - <string name="biometric_not_recognized" msgid="5106687642694635888">"မသိ"</string> + <string name="biometric_not_recognized" msgid="5106687642694635888">"မသိပါ"</string> <string name="biometric_face_not_recognized" msgid="5535599455744525200">"မျက်နှာကို မသိရှိပါ"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"အထောက်အထားစိစစ်ခြင်းကို ပယ်ဖျက်လိုက်သည်"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"ပင်နံပါတ်၊ လော့ခ်ပုံစံ သို့မဟုတ် စကားဝှက် သတ်မှတ်မထားပါ"</string> @@ -2220,7 +2220,7 @@ <string name="miniresolver_switch_to_work" msgid="1042640606122638596">"အလုပ်သုံးအက်ပ်သို့ ပြောင်းမလား။"</string> <string name="miniresolver_call_information" msgid="6739417525304184083">"သင့်အဖွဲ့အစည်းသည် သင့်အား အလုပ်သုံးအက်ပ်များမှသာ ဖုန်းဆက်ခွင့်ပြုသည်"</string> <string name="miniresolver_sms_information" msgid="4311292661329483088">"သင့်အဖွဲ့အစည်းသည် သင့်အား အလုပ်သုံးအက်ပ်များမှသာ မက်ဆေ့ဂျ်ပို့ခွင့်ပြုသည်"</string> - <string name="miniresolver_private_space_phone_information" msgid="4469511223312488570">"သင့်ကိုယ်ပိုင် ‘ဖုန်းအက်ပ်’ မှသာ ဖုန်းခေါ်ဆိုနိုင်သည်။ ကိုယ်ပိုင် ‘ဖုန်း’ ဖြင့် ပြုလုပ်သော ခေါ်ဆိုမှုများကို သင်၏ကိုယ်ပိုင် ခေါ်ဆိုမှုမှတ်တမ်းသို့ ထည့်ပါမည်။"</string> + <string name="miniresolver_private_space_phone_information" msgid="4469511223312488570">"သင့်ကိုယ်ပိုင် ‘ဖုန်းအက်ပ်’ မှသာ ဖုန်းခေါ်ဆိုနိုင်သည်။ ကိုယ်ပိုင် ‘ဖုန်း’ ဖြင့် ခေါ်ဆိုမှုများကို သင်၏ ကိုယ်ပိုင် ခေါ်ဆိုမှုမှတ်တမ်းသို့ ထည့်ပါမည်။"</string> <string name="miniresolver_private_space_messages_information" msgid="111285656327622118">"သင့်ကိုယ်ပိုင် Messages အက်ပ်မှသာ SMS မက်ဆေ့ဂျ်များကို ပို့နိုင်သည်။"</string> <string name="miniresolver_use_personal_browser" msgid="776072682871133308">"ကိုယ်ပိုင်ဘရောင်ဇာ သုံးရန်"</string> <string name="miniresolver_use_work_browser" msgid="543575306251952994">"အလုပ်သုံးဘရောင်ဇာ သုံးရန်"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ဖွင့်ရန်"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"အလုပ်လုပ်ပုံ"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"ဆိုင်းငံ့ထားသည်…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index c4c705c5a942..ad4ffc202466 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -156,7 +156,7 @@ <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Sikkerhet for mobilnettverk"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Kryptering, varsler for ukrypterte nettverk"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Enhets-ID-en er lest"</string> - <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> registrerte et nettverk i nærheten den unike ID-en (IMSI eller IMEI) til enheten din mens du brukte SIM-kortet fra <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>"</string> + <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> registrerte et nettverk i nærheten enhetens unike ID (IMSI eller IMEI) mens du brukte <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>-SIM-kortet"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> registrerte et nettverk i nærheten den unike ID-en (IMSI eller IMEI) til enheten din mens du brukte SIM-kortet fra <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>.\n\nDette betyr at posisjonen, aktiviteten eller identiteten din er registrert. Dette er en vanlig praksis, men kan være et problem for folk som er opptatt av personvern."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Koblet til det krypterte nettverket <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Tilkoblingen til SIM-kortet fra <xliff:g id="NETWORK_NAME">%1$s</xliff:g> er sikrere nå"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Åpne Meldinger"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Slik fungerer det"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Venter …"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 559f07a3e6da..1cde247403c3 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -156,8 +156,8 @@ <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"मोबाइल नेटवर्कको सुरक्षा"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"इन्क्रिप्सन, इन्क्रिप्ट नगरिएका नेटवर्कसम्बन्धी सूचना"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"डिभाइसको ID एक्सेस गरियो"</string> - <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"तपाईंले आफ्नो <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM प्रयोग गर्दै गर्दा तपाईंको डिभाइसको नजिकै रहेको एउटा नेटवर्कले <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> बजे तपाईंको डिभाइसको अद्वितीय ID रेकर्ड गरेको छ"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"तपाईंले आफ्नो <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM प्रयोग गर्दै गर्दा तपाईंको डिभाइसको नजिकै रहेको एउटा नेटवर्कले <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> बजे तपाईंको डिभाइसको अद्वितीय ID रेकर्ड गरेको छ।\n\nयसको अर्थ तपाईंको लोकेसन, गतिविधि वा पहिचान लग गरिएको छ। यसो गर्नु सामान्य हो तर आफ्नो गोपनीयताका बारेमा चिन्ता लिने मान्छेहरूका लागि यो समस्याको विषय हुन सक्छ।"</string> + <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"तपाईंले आफ्नो <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM प्रयोग गर्दै गर्दा तपाईंको डिभाइसको नजिकै रहेको एउटा नेटवर्कले <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> मा तपाईंको डिभाइसको अद्वितीय ID रेकर्ड गरेको छ"</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"तपाईंले आफ्नो <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM प्रयोग गर्दै गर्दा तपाईंको डिभाइसको नजिकै रहेको एउटा नेटवर्कले <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> मा तपाईंको डिभाइसको अद्वितीय ID रेकर्ड गरेको छ।\n\nयसको अर्थ तपाईंको लोकेसन, गतिविधि वा पहिचान लग गरिएको छ। यसो गर्नु सामान्य हो तर आफ्नो गोपनीयताका बारेमा चिन्ता लिने मान्छेहरूका लागि यो समस्याको विषय हुन सक्छ।"</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"इन्क्रिप्ट गरिएको नेटवर्क <xliff:g id="NETWORK_NAME">%1$s</xliff:g> मा कनेक्ट गरियो"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM को कनेक्सन अब सुरक्षित छ"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"इन्क्रिप्ट नगरिएको नेटवर्कमा कनेक्ट गरियो"</string> @@ -466,11 +466,11 @@ <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"औपचारिक प्रसारणलाई पठाउनको लागि एउटा एपलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले ट्याब्लेटलाई ढिलो र अस्थिर बनाउन सक्छ।"</string> <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"एपलाई प्रसारण समाप्त भइसकेपछि पनि रहिरहने स्टिकी प्रसारणहरू पठाउने अनुमति दिन्छ। यो सुविधाको अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग हुने भएकाले तपाईंको Android टिभी यन्त्र सुस्त वा अस्थिर हुन सक्छ।"</string> <string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"औपचारिक प्रसारणलाई पठाउनको लागि एक एपलाई अनुमति दिन्छ, जुन प्रसारण समाप्त भएपछि बाँकी रहन्छ। अत्यधिक प्रयोगले धेरै मेमोरी प्रयोग गरेको कारणले फोनलाई ढिलो र अस्थिर बनाउन सक्छ।"</string> - <string name="permlab_readContacts" msgid="8776395111787429099">"तपाईँका सम्पर्कहरू पढ्नुहोस्"</string> + <string name="permlab_readContacts" msgid="8776395111787429099">"तपाईँका कन्ट्याक्टहरू पढ्नुहोस्"</string> <string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"एपलाई तपाईंको ट्याब्लेटमा भण्डारण गरिएका कन्ट्याक्टहरूसँग सम्बन्धित डेटा पढ्ने अनुमति दिन्छ। एपहरूले कन्ट्याक्टहरू बनाउने तपाईंको ट्याब्लेटमा भण्डारण गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका एपहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले एपहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सेभ गर्न दिने भएकाले हानिकारक एपहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string> <string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"एपलाई तपाईंको Android टिभी डिभाइसमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा पढ्न अनुमति दिन्छ। एपहरूले कन्ट्याक्टहरू बनाउने तपाईंको Android टिभी डिभाइसमा भण्डारण गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका एपहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले एपहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सेभ गर्न दिने भएकाले हानिकारक एपहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string> <string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"एपलाई तपाईंको फोनमा भण्डारण गरिएका कन्ट्याक्टहरूसँग सम्बन्धित डेटा पढ्ने अनुमति दिन्छ। एपहरूले कन्ट्याक्टहरू बनाउने तपाईंको फोनमा भण्डारण गरिएका खाताहरूमाथि पनि पहुँच प्राप्त गर्ने छन्। यसमा तपाईंले स्थापना गरेका एपहरूले बनाएका खाताहरू पर्न सक्छन्। यस अनुमतिले एपहरूलाई तपाईंको सम्पर्क ठेगानासम्बन्धी डेटा सेभ गर्न दिने भएकाले हानिकारक एपहरूले तपाईंलाई थाहै नदिइकन सम्पर्क ठेगानासम्बन्धी डेटा आदान प्रदान गर्न सक्छन्।"</string> - <string name="permlab_writeContacts" msgid="8919430536404830430">"तपाईँका सम्पर्कहरू परिवर्तन गर्नुहोस्"</string> + <string name="permlab_writeContacts" msgid="8919430536404830430">"तपाईँका कन्ट्याक्टहरू परिवर्तन गर्नुहोस्"</string> <string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"एपलाई तपाईंको ट्याब्लेटमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले एपलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string> <string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"एपलाई तपाईंको Android टिभी डिभाइसमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले एपलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string> <string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"एपलाई तपाईंको फोनमा भण्डारण गरिएका सम्पर्क ठेगानासम्बन्धी डेटा परिमार्जन गर्न अनुमति दिन्छ। यो अनुमतिले एपलाई सम्पर्क ठेगानासम्बन्धी डेटा मेटाउन अनुमति दिन्छ।"</string> @@ -645,7 +645,7 @@ <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"बायोमेट्रिक हार्डवेयर उपलब्ध छैन"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"प्रमाणीकरण रद्द गरियो"</string> <string name="biometric_not_recognized" msgid="5106687642694635888">"पहिचान भएन"</string> - <string name="biometric_face_not_recognized" msgid="5535599455744525200">"अनुहार पहिचान गर्न सकिएन"</string> + <string name="biometric_face_not_recognized" msgid="5535599455744525200">"अनुहार मिलेन"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"प्रमाणीकरण रद्द गरियो"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"कुनै पनि PIN, ढाँचा वा पासवर्ड सेट गरिएको छैन"</string> <string name="biometric_error_generic" msgid="6784371929985434439">"प्रमाणित गर्ने क्रममा त्रुटि भयो"</string> @@ -666,7 +666,7 @@ </string-array> <string name="fingerprint_error_not_match" msgid="4599441812893438961">"फिंगरप्रिन्ट मिलेन"</string> <string name="fingerprint_udfps_error_not_match" msgid="8236930793223158856">"फिंगरप्रिन्ट मिलेन"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5590293588784953188">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string> + <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5590293588784953188">"अनुहार मिलेन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string> <string name="fingerprint_authenticated" msgid="2024862866860283100">"फिंगरप्रिन्ट प्रमाणीकरण गरियो"</string> <string name="face_authenticated_no_confirmation_required" msgid="8867889115112348167">"अनुहार प्रमाणीकरण गरियो"</string> <string name="face_authenticated_confirmation_required" msgid="6872632732508013755">"अनुहार प्रमाणीकरण गरियो, कृपया पुष्टि गर्नुहोस् थिच्नुहोस्"</string> @@ -716,7 +716,7 @@ <string name="face_acquired_not_detected" msgid="1057966913397548150">"तपाईंको अनुहार देखिएन। तपाईंको फोन आफ्नो आँखाअघि राखी समात्नुहोस्।"</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"अत्यधिक हल्लियो। फोन स्थिर राख्नुहोस्।"</string> <string name="face_acquired_recalibrate" msgid="8724013080976469746">"कृपया आफ्नो अनुहार पुनः दर्ता गर्नुहोस्।"</string> - <string name="face_acquired_too_different" msgid="4505278456634706967">"अनुहार पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string> + <string name="face_acquired_too_different" msgid="4505278456634706967">"अनुहार मिलेन। फेरि प्रयास गर्नुहोस्।"</string> <string name="face_acquired_too_similar" msgid="8882920552674125694">"आफ्नो टाउको थोरै यताउता सार्नुहोस्"</string> <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"आफ्नो फोनमा अझ सीधा हेर्नुहोस्"</string> <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"आफ्नो फोनमा अझ सीधा हेर्नुहोस्"</string> @@ -1507,7 +1507,7 @@ <string name="ime_action_previous" msgid="6548799326860401611">"अघिल्लो"</string> <string name="ime_action_default" msgid="8265027027659800121">"चलाउनुहोस्"</string> <string name="dial_number_using" msgid="6060769078933953531">\n"नम्बर डायल गर्नुहोस् <xliff:g id="NUMBER">%s</xliff:g> प्रयोग गरेर"</string> - <string name="create_contact_using" msgid="6200708808003692594">"सम्पर्क सिर्जना गर्नुहोस्\nयो <xliff:g id="NUMBER">%s</xliff:g> प्रयोग गरेर"</string> + <string name="create_contact_using" msgid="6200708808003692594">"कन्ट्याक्ट हाल्नुहोस्\nयो <xliff:g id="NUMBER">%s</xliff:g> प्रयोग गरेर"</string> <string name="grant_credentials_permission_message_header" msgid="5365733888842570481">"निम्न एउटा वा धेरै एपहरूले तपाईँको खातामा पहुँचको लागि अनुमति अहिले र भविष्यमा अनुरोध गर्छन्।"</string> <string name="grant_credentials_permission_message_footer" msgid="1886710210516246461">"के तपाईं यस अनुरोधलाई अनुमति दिन चाहनुहुन्छ?"</string> <string name="grant_permissions_header_text" msgid="3420736827804657201">"अनुरोध पहुँच गर्नुहोस्"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages खोल्नुहोस्"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"यसले काम गर्ने तरिका"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"विचाराधीन..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 5c393af52d37..7bae96e6ab88 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -159,9 +159,9 @@ <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Om <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> heeft een netwerk in de buurt de unieke ID van je apparaat (IMSI of IMEI) geregistreerd toen je je simkaart van <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> gebruikte"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Om <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> heeft een netwerk in de buurt de unieke ID van je apparaat (IMSI of IMEI) geregistreerd toen je je simkaart van <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> gebruikte.\n\nDit betekent dat je locatie, activiteit of identiteit is geregistreerd. Dit is gebruikelijk, maar kan een probleem zijn voor mensen die zich zorgen maken over privacy."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Verbonden met versleuteld netwerk <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> - <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"De verbinding van de simkaart van <xliff:g id="NETWORK_NAME">%1$s</xliff:g> is nu beter beveiligd"</string> + <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"De verbinding van de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-sim is nu beter beveiligd"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Verbonden met een niet-versleuteld netwerk"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Gesprekken, berichten en gegevens zijn op dit moment kwetsbaarder tijdens het gebruik van je simkaart van <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Gesprekken, berichten en gegevens zijn op dit moment kwetsbaarder tijdens het gebruik van je <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-sim"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Gesprekken, berichten en gegevens zijn op dit moment kwetsbaarder tijdens het gebruik van je simkaart van <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nAls je verbinding weer versleuteld is, krijg je opnieuw een melding."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Instellingen voor beveiliging van mobiel netwerk"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Meer informatie"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Berichten openen"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Hoe het werkt"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"In behandeling…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index e6fa56248b0f..c00998acbe16 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -156,7 +156,7 @@ <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"ମୋବାଇଲ ନେଟୱାର୍କ ସୁରକ୍ଷା"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"ଏନକ୍ରିପସନ, ଏନକ୍ରିପ୍ଟ କରାଯାଇନଥିବା ନେଟୱାର୍କ ପାଇଁ ବିଜ୍ଞପ୍ତି"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"ଡିଭାଇସ ID ଆକ୍ସେସ କରାଯାଇଛି"</string> - <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"ଆପଣଙ୍କ <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> ରେକର୍ଡ କରିବା ସମୟରେ <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>ରେ ଏକ ଆଖପାଖର ନେଟୱାର୍କ ଆପଣଙ୍କ ଡିଭାଇସର ସ୍ୱତନ୍ତ୍ର ID (IMSI କିମ୍ବା IMEI) ରେକର୍ଡ କରିଛି"</string> + <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"ଆପଣଙ୍କ <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM ବ୍ୟବହାର କରିବା ସମୟରେ <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>ରେ ଏକ ଆଖପାଖର ନେଟୱାର୍କ ଆପଣଙ୍କ ଡିଭାଇସର ସ୍ୱତନ୍ତ୍ର ID (IMSI କିମ୍ବା IMEI) ରେକର୍ଡ କରିଛି"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"ଆପଣଙ୍କ <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM ବ୍ୟବହାର କରିବା ସମୟରେ <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>ରେ ଏକ ଆଖପାଖର ନେଟୱାର୍କ ଆପଣଙ୍କ ଡିଭାଇସର ସ୍ୱତନ୍ତ୍ର ID (IMSI କିମ୍ବା IMEI) ରେକର୍ଡ କରିଛି। \n\nଏହାର ଅର୍ଥ ହେଉଛି ଯେ ଆପଣଙ୍କ ଲୋକେସନ, କାର୍ଯ୍ୟକଳାପ କିମ୍ବା ପରିଚୟକୁ ଲଗ କରାଯାଇଛି। ଏହା ସାଧାରଣ ଅଭ୍ୟାସ ଅଟେ କିନ୍ତୁ ଗୋପନୀୟତା ବିଷୟରେ ଚିନ୍ତିତ ଲୋକମାନଙ୍କ ପାଇଁ ଏହା ଏକ ସମସ୍ୟା ହୋଇପାରେ।"</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"ଏନକ୍ରିପ୍ଟ କରାଯାଇଥିବା ନେଟୱାର୍କ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ସହ କନେକ୍ଟ କରାଯାଇଛି"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM କନେକ୍ସନ ବର୍ତ୍ତମାନ ଅଧିକ ସୁରକ୍ଷିତ ଅଟେ"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ଖୋଲନ୍ତୁ"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ଏହା କିପରି କାମ କରେ"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"ବାକି ଅଛି…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index e2586e6a9b78..77020acff650 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -161,8 +161,8 @@ <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"ਇਨਕ੍ਰਿਪਟਡ ਨੈੱਟਵਰਕ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਸਿਮ ਕਨੈਕਸ਼ਨ ਹੁਣ ਜ਼ਿਆਦਾ ਸੁਰੱਖਿਅਤ ਹੈ"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"ਇਨਕ੍ਰਿਪਟਡ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"ਫ਼ਿਲਹਾਲ ਤੁਹਾਡੇ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਸਿਮ ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਕਾਲਾਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਡਾਟਾ ਜ਼ਿਆਦਾ ਖਤਰੇ ਵਿੱਚ ਹਨ"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"ਫ਼ਿਲਹਾਲ ਤੁਹਾਡੇ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਸਿਮ ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਕਾਲਾਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਡਾਟਾ ਜ਼ਿਆਦਾ ਖਤਰੇ ਵਿੱਚ ਹਨ।\n\nਤੁਹਾਡਾ ਕਨੈਕਸ਼ਨ ਦੁਬਾਰਾ ਇਨਕ੍ਰਿਪਟਡ ਹੋਣ \'ਤੇ, ਤੁਹਾਨੂੰ ਹੋਰ ਸੂਚਨਾ ਪ੍ਰਾਪਤ ਹੋਵੇਗੀ।"</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"ਫ਼ਿਲਹਾਲ ਤੁਹਾਡੇ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਸਿਮ ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਸਮੇਂ ਕਾਲਾਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ ਕੀਤੇ ਜਾਣ ਦਾ ਖਤਰਾ ਰਹਿੰਦਾ ਹੈ"</string> + <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> @@ -316,7 +316,7 @@ <string name="managed_profile_app_label" msgid="367401088383965725">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ \'ਤੇ ਜਾਓ"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"ਸੰਪਰਕ"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"ਆਪਣੇ ਸੰਪਰਕਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string> - <string name="permgrouplab_location" msgid="1858277002233964394">"ਟਿਕਾਣਾ"</string> + <string name="permgrouplab_location" msgid="1858277002233964394">"ਟਿਕਾਣੇ ਦੀ ਜਾਣਕਾਰੀ"</string> <string name="permgroupdesc_location" msgid="1995955142118450685">"ਇਸ ਡੀਵਾਈਸ ਦੇ ਨਿਰਧਾਰਤ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚੋ"</string> <string name="permgrouplab_calendar" msgid="6426860926123033230">"ਕੈਲੰਡਰ"</string> <string name="permgroupdesc_calendar" msgid="6762751063361489379">"ਤੁਹਾਡੇ ਕੈਲੰਡਰ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ਐਪ ਖੋਲ੍ਹੋ"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ਇਹ ਕਿਵੇਂ ਕੰਮ ਕਰਦਾ ਹੈ"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"ਵਿਚਾਰ-ਅਧੀਨ..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index d5c8d763bf0e..0971ae40d500 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -161,9 +161,9 @@ <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"O godzinie <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> pobliska sieć zarejestrowała unikalny identyfikator Twojego urządzenia (IMSI lub IMEI) podczas korzystania z karty SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"O godzinie <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> pobliska sieć zarejestrowała unikalny identyfikator Twojego urządzenia (IMSI lub IMEI) podczas korzystania z karty SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>.\n\nOznacza to, że zarejestrowano Twoją lokalizację, aktywność lub tożsamość. Jest to powszechna praktyka, ale może stanowić problem dla osób dbających o prywatność."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Połączono z szyfrowaną siecią <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> - <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Połączenie SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> jest teraz bezpieczniejsze"</string> + <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Połączenie przy użyciu karty SIM w sieci <xliff:g id="NETWORK_NAME">%1$s</xliff:g> jest teraz bezpieczniejsze"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Połączono z niezaszyfrowaną siecią"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Połączenia, wiadomości i dane są obecnie bardziej podatne na ataki podczas korzystania z karty SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Gdy korzystasz z karty SIM w sieci <xliff:g id="NETWORK_NAME">%1$s</xliff:g>, połączenia, wiadomości i dane są bardziej narażone na ataki"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Połączenia, wiadomości i dane są obecnie bardziej podatne na ataki podczas korzystania z karty SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nGdy połączenie zostanie ponownie zaszyfrowane, otrzymasz kolejne powiadomienie."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Ustawienia bezpieczeństwa sieci komórkowej"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Więcej informacji"</string> @@ -2415,4 +2415,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otwórz Wiadomości"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Jak to działa"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Oczekiwanie…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 4d9e208233a8..b04cd4c6ed98 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -164,7 +164,7 @@ <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Conectado à rede não criptografada"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Suas ligações, mensagens e dados estão mais vulneráveis no momento ao usar seu chip da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Ligações, mensagens e dados estão mais vulneráveis no momento ao usar seu chip da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nQuando a conexão for criptografada novamente, você vai receber outra notificação."</string> - <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Configurações de segurança de rede móvel"</string> + <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Configurações de segurança da rede móvel"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Saiba mais"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"Entendi"</string> <string name="fcComplete" msgid="1080909484660507044">"Código de recurso concluído."</string> @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir o app Mensagens"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 2074d1e85868..90f9eda9c32e 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1389,7 +1389,7 @@ <string name="no_permissions" msgid="5729199278862516390">"Não são necessárias permissões"</string> <string name="perm_costs_money" msgid="749054595022779685">"isto poderá estar sujeito a custos"</string> <string name="dlg_ok" msgid="5103447663504839312">"OK"</string> - <string name="usb_charging_notification_title" msgid="1674124518282666955">"O dispositivo está a carregar por USB"</string> + <string name="usb_charging_notification_title" msgid="1674124518282666955">"O dispositivo está a ser carregado por USB"</string> <string name="usb_supplying_notification_title" msgid="5378546632408101811">"A carregar o dispositivo ligado por USB"</string> <string name="usb_mtp_notification_title" msgid="1065989144124499810">"A transferência de ficheiros por USB está ativada"</string> <string name="usb_ptp_notification_title" msgid="5043437571863443281">"O PTP por USB está ativado"</string> @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abre a app Mensagens"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 4d9e208233a8..b04cd4c6ed98 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -164,7 +164,7 @@ <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Conectado à rede não criptografada"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Suas ligações, mensagens e dados estão mais vulneráveis no momento ao usar seu chip da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Ligações, mensagens e dados estão mais vulneráveis no momento ao usar seu chip da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nQuando a conexão for criptografada novamente, você vai receber outra notificação."</string> - <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Configurações de segurança de rede móvel"</string> + <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Configurações de segurança da rede móvel"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Saiba mais"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"Entendi"</string> <string name="fcComplete" msgid="1080909484660507044">"Código de recurso concluído."</string> @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Abrir o app Mensagens"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Como funciona"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Pendente…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 10aa0207bf85..c43df4fa6e41 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Deschide Mesaje"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cum funcționează"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"În așteptare..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index ff0d1b8818ca..32a2338b284d 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -158,11 +158,11 @@ <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Безопасность мобильной сети"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Шифрование, уведомления о незашифрованных сетях"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Получен доступ к идентификатору устройства"</string> - <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"В <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> при использовании SIM-карты (<xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>) в сети поблизости был записан уникальный идентификатор вашего устройства (IMSI или IMEI)."</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"В <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> при использовании SIM-карты (<xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>) в сети поблизости был записан уникальный идентификатор вашего устройства (IMSI или IMEI).\n\nВаше местоположение, действия или личность были зарегистрированы. Хотя в этом нет ничего необычного, раскрытие данных может доставлять проблемы людям, которые беспокоятся о своей конфиденциальности."</string> - <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Подключение к зашифрованной сети \"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>\""</string> - <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Теперь подключение SIM-карты (<xliff:g id="NETWORK_NAME">%1$s</xliff:g>) более безопасное."</string> - <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Подключение к незашифрованной сети"</string> + <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"В <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, когда вы использовали SIM-карту \"<xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>\", сетью поблизости от вас был записан уникальный идентификатор вашего устройства (IMSI или IMEI)."</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"В <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, когда вы использовали SIM-карту \"<xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>\", сетью поблизости от вас был записан уникальный идентификатор вашего устройства (IMSI или IMEI).\n\nЭто значит, что было зарегистрировано ваше местоположение, действия или личность. Это распространенная практика, однако она может вызывать беспокойство у тех, кто заботится о своей конфиденциальности."</string> + <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Подключено к зашифрованной сети <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> + <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Теперь подключение SIM-карты (<xliff:g id="NETWORK_NAME">%1$s</xliff:g>) лучше защищено."</string> + <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Подключено к незашифрованной сети"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Сейчас звонки, сообщения и данные более уязвимы при использовании SIM-карты (<xliff:g id="NETWORK_NAME">%1$s</xliff:g>)."</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Сейчас звонки, сообщения и данные более уязвимы при использовании SIM-карты (<xliff:g id="NETWORK_NAME">%1$s</xliff:g>).\n\nКогда соединение будет снова зашифровано, вы получите ещё одно уведомление."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Настройки безопасности мобильной сети"</string> @@ -2415,4 +2415,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Открыть Сообщения"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Узнать принцип работы"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Обработка…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index 18b26f27816b..9539cef0f26c 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages විවෘත කරන්න"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"එය ක්රියා කරන ආකාරය"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"පොරොත්තුයි..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 3b144d27905f..c72a426d0436 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -163,8 +163,8 @@ <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Pripojené k šifrovanej sieti <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Pripojenie SIM siete <xliff:g id="NETWORK_NAME">%1$s</xliff:g> je teraz zabezpečenejšie"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Pripojené k nešifrovanej sieti"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Hovory, správy a údaje sú momentálne zraniteľnejšie vzhľadom na nedostatok zabezpečenia pri používaní SIM siete <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Hovory, správy a údaje sú momentálne zraniteľnejšie vzhľadom na nedostatok zabezpečenia pri používaní SIM siete <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nKeď bude vaše pripojenie znova šifrované, dostanete ďalšie upozornenie."</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Pri používaní SIM siete <xliff:g id="NETWORK_NAME">%1$s</xliff:g> sú vaše hovory, správy a údaje zraniteľnejšie"</string> + <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Pri používaní SIM siete <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nsú vaše hovory, správy a údaje zraniteľnejšie. Keď bude vaše pripojenie znova šifrované, dostanete ďalšie upozornenie."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Nastavenia zabezpečenia mobilnej siete"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Ďalšie informácie"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"Dobre"</string> @@ -2415,4 +2415,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Otvoriť Správy"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ako to funguje"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Nespracovaná…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 1b7a2a145f80..e1be803cce1b 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -2415,4 +2415,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Odpri Sporočila"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Kako deluje"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"V teku …"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 142ab0d663d6..4d79ce707787 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -157,12 +157,12 @@ <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Enkriptimi, njoftimet për rrjetet e paenkriptuara"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Pati qasje tek ID-ja e pajisjes"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Në <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, një rrjet në afërsi ka regjistruar ID-në unike (IMSI ose IMEI) të pajisjes sate gjatë përdorimit të kartës sate SIM të <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Në <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, një rrjet në afërsi ka regjistruar ID-në unike (IMSI ose IMEI) të pajisjes sate gjatë përdorimit të kartës sate SIM të <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>.\n\nKjo do të thotë që vendndodhja, aktiviteti ose identiteti yt janë regjistruar. Kjo është një praktikë të zakonshme, por mund të jetë problem për personat që janë të shqetësuar në lidhje me privatësinë."</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Në <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, një rrjet në afërsi ka regjistruar ID-në unike (IMSI ose IMEI) të pajisjes sate gjatë përdorimit të kartës sate SIM të <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>.\n\nKjo do të thotë që vendndodhja, aktiviteti ose identiteti yt janë regjistruar. Kjo është një praktikë e zakonshme, por mund të jetë problem për personat që janë të shqetësuar në lidhje me privatësinë."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Lidhur me rrjetin e enkriptuar <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Lidhja e kartës SIM të <xliff:g id="NETWORK_NAME">%1$s</xliff:g> është më e sigurt tani"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Lidhur me një rrjet të paenkriptuar"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Telefonatat, mesazhet dhe të dhënat janë aktualisht më të cenueshme ndërkohë që përdoret karta jote SIM të <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Telefonatat, mesazhet dhe të dhënat janë aktualisht më të cenueshme ndërkohë që përdoret karta jote SIM të <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nKur lidhja jote të jetë përsëri e enkriptuar, do të marrësh një njoftim tjetër."</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Telefonatat, mesazhet dhe të dhënat janë aktualisht më të cenueshme teksa përdoret karta SIM e <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> + <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Telefonatat, mesazhet dhe të dhënat janë aktualisht më të cenueshme teksa përdoret karta SIM e <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nKur lidhja jote të jetë përsëri e enkriptuar, do të marrësh një njoftim tjetër."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Cilësimet e sigurisë së rrjetit celular"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Mëso më shumë"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"E kuptova"</string> @@ -2144,10 +2144,8 @@ <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Njoftimi i informacionit të \"Modalitetit rutinë\""</string> <string name="dynamic_mode_notification_title" msgid="1388718452788985481">"\"Kursyesi i baterisë\" u aktivizua"</string> <string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Po reduktohet përdorimi i baterisë për të rritur kohëzgjatjen e baterisë"</string> - <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) --> - <skip /> - <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) --> - <skip /> + <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"\"Kursyesi i baterisë\" është aktiv"</string> + <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"\"Kursyesi i baterisë\" është aktivizuar për të zgjatur kohëzgjatjen e baterisë"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Kursyesi i baterisë"</string> <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"\"Kursyesi i baterisë\" është çaktivizuar"</string> <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Telefoni ka nivel të mjaftueshëm baterie. Funksionet nuk janë më të kufizuara."</string> @@ -2415,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Hap \"Mesazhet\""</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Si funksionon"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Në pritje..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 87d10860a0b0..95ccead79ce2 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -161,7 +161,7 @@ <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Мрежа у близини је у <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> евидентирала јединствени ИД вашег уређаја (IMSI или IMEI) док сте користили <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM.\n\nТо значи да је евидентирала вашу локацију, активност и идентитет. То је уобичајена пракса, али може да буде проблем људима који су забринути за приватност."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Повезани сте на шифровану мрежу <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Веза <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM-а је сада безбеднија"</string> - <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Повезани сте на шифровану мрежу"</string> + <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Повезани сте на нешифровану мрежу"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Позиви, поруке и подаци су тренутно рањивији док користите <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Позиви, поруке и подаци су тренутно рањивији док користите <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM.\n\nКада веза поново буде шифрована, послаћемо вам друго обавештење."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Подешавања безбедности на мобилној мрежи"</string> @@ -2414,4 +2414,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Отвори Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Принцип рада"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"На чекању..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 3ca5c9fcb4ab..0cbdda1a4c27 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Öppna Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Så fungerar det"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Väntar …"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 2efca2b4a891..10f55af3dc47 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -161,8 +161,8 @@ <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Imeunganishwa kwenye mtandao uliosimbwa kwa njia fiche wa <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Sasa muunganisho wa SIM wa <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ni salama zaidi"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Imeunganishwa kwenye mtandao ambao haujasimbwa kwa njia fiche"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Kwa sasa maudhui ya simu, ujumbe na data yako katika hatari ya kuvamiwa unapotumia SIM yako ya <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> - <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Kwa sasa maudhui ya simu, ujumbe na data yako katika hatari ya kuvamiwa unapotumia SIM yako ya <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nMuunganisho wako ukisimbwa kwa njia fiche tena, utapata arifa nyingine."</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Kwa sasa maudhui ya simu, ujumbe na data ipo katika hatari ya kuvamiwa unapotumia SIM yako ya <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> + <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Kwa sasa maudhui ya simu, ujumbe na data ipo katika hatari ya kuvamiwa unapotumia SIM yako ya <xliff:g id="NETWORK_NAME">%1$s</xliff:g>.\n\nMuunganisho wako ukisimbwa kwa njia fiche tena, utapata arifa nyingine."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Mipangilio ya usalama wa mtandao wa simu"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Pata maelezo zaidi"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"Nimeelewa"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Fungua Programu ya Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Utaratibu wake"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Inashughulikiwa..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 0c704e353836..466e29a7e9b1 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messages ஆப்ஸைத் திறக்கவும்"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"இது செயல்படும் விதம்"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"நிலுவையிலுள்ளது..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index b465000e9690..db75aac8b027 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -156,7 +156,7 @@ <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"మొబైల్ నెట్వర్క్ సెక్యూరిటీ"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"ఎన్క్రిప్షన్, ఎన్క్రిప్ట్ చేయని నెట్వర్క్లకు సంబంధించిన నోటిఫికేషన్లు"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"పరికర IDని యాక్సెస్ చేశారు"</string> - <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"మీ <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIMను ఉపయోగిస్తున్నప్పుడు, సమీపంలోని నెట్వర్క్ <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> సమయానికి మీ పరికర యూనిక్ ID (IMSI లేదా IMEI)ని రికార్డ్ చేసింది"</string> + <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"మీ <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIMను వాడేటప్పుడు, <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>కి దగ్గర్లోని ఒక నెట్వర్క్, మీ పరికర యూనిక్ IDని (IMSI లేదా IMEI) రికార్డ్ చేసింది"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"మీ <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIMను ఉపయోగిస్తున్నప్పుడు, సమీపంలోని నెట్వర్క్ <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> సమయానికి మీ పరికర యూనిక్ ID (IMSI లేదా IMEI)ని రికార్డ్ చేసింది.\n\nమీ లొకేషన్, యాక్టివిటీ, లేదా గుర్తింపు లాగ్ అయ్యాయని దీని అర్థం. దీనిని తరచుగా అమలు చేస్తుంటారు, కానీ గోప్యత గురించి ఆందోళనపడే వ్యక్తులకు ఇది సమస్య కావచ్చు,"</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"ఎన్క్రిప్ట్ చేసిన నెట్వర్క్ <xliff:g id="NETWORK_NAME">%1$s</xliff:g>కు కనెక్ట్ అయింది"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM కనెక్షన్ ఇప్పుడు మరింత సురక్షితంగా ఉంది"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Messagesను తెరవండి"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"ఇది ఎలా పని చేస్తుంది"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"పెండింగ్లో ఉంది..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 535396de7936..284a5f273f22 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -1619,7 +1619,7 @@ <string name="data_usage_mobile_limit_snoozed_title" msgid="101888478915677895">"เกินปริมาณเน็ตมือถือที่กำหนดไว้"</string> <string name="data_usage_wifi_limit_snoozed_title" msgid="1622359254521960508">"เกินขีดจำกัดของข้อมูล Wi-Fi"</string> <string name="data_usage_limit_snoozed_body" msgid="545146591766765678">"คุณใช้อินเทอร์เน็ตเกินไป <xliff:g id="SIZE">%s</xliff:g> จากปริมาณที่กำหนดไว้"</string> - <string name="data_usage_restricted_title" msgid="126711424380051268">"จำกัดอินเทอร์เน็ตที่ใช้งานอยู่เบื้องหลัง"</string> + <string name="data_usage_restricted_title" msgid="126711424380051268">"จำกัดข้อมูลในเบื้องหลัง"</string> <string name="data_usage_restricted_body" msgid="5338694433686077733">"แตะเพื่อนำข้อจำกัดออก"</string> <string name="data_usage_rapid_title" msgid="2950192123248740375">"ปริมาณการใช้เน็ตมือถือสูง"</string> <string name="data_usage_rapid_body" msgid="3886676853263693432">"แอปของคุณใช้อินเทอร์เน็ตมากกว่าปกติ"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"เปิด Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"วิธีการทำงาน"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"รอดำเนินการ..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 6eab396ca97c..4dd488681f5b 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -161,7 +161,7 @@ <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Nakakonekta sa naka-encrypt na network na <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Mas secure na ang koneksyon ng <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Nakakonekta sa hindi naka-encrypt na network"</string> - <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Kasalukuyang mas nanganganib ang mga tawag, mensahe, at data habang ginagamit ang iyong <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM"</string> + <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Kasalukuyang walang proteksyon ang tawag, mensahe, at data habang gamit ang <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM mo"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Kasalukuyang mas nanganganib ang mga tawag, mensahe, at data habang ginagamit ang iyong <xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM.\n\nKapag na-encrypt ulit ang iyong koneksyon, makakatanggap ka ng isa pang notification."</string> <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Mga setting ng seguridad ng mobile network"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Matuto pa"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Buksan ang Messages"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Paano ito gumagana"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Nakabinbin..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 4c8083a754a5..2b616defdaa6 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Mesajlar\'ı aç"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"İşleyiş şekli"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Bekliyor..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 6f94a2cf4e51..850e21b15ef9 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -2146,10 +2146,8 @@ <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Сповіщення про програму"</string> <string name="dynamic_mode_notification_title" msgid="1388718452788985481">"Режим енергозбереження ввімкнено"</string> <string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"Заряд використовується економно, щоб подовжити час роботи акумулятора"</string> - <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) --> - <skip /> - <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) --> - <skip /> + <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"Режим енергозбереження ввімкнено"</string> + <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"Увімкнено режим енергозбереження, щоб збільшити час роботи акумулятора"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Режим енергозбереження"</string> <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Режим енергозбереження вимкнено."</string> <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Телефон має достатньо заряду акумулятора. Функції вже не обмежено."</string> @@ -2417,4 +2415,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Відкрийте Повідомлення"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Як це працює"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Обробка…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index ed1a358d19a8..d3fde3c4f455 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -157,7 +157,7 @@ <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"غیر مرموز کردہ نیٹ ورکس کے لیے مرموز کاری، اطلاعات"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"آلہ ID تک رسائی کی گئی"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> میں، قریبی نیٹ ورک نے آپ کے <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM کا استعمال کرتے ہوئے آپ کے آلے کی منفرد ID (IMSI یا IMEI) ریکارڈ کی"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> میں، آپ کے <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM استعمال کرتے ہوئے قریبی نیٹ ورک نے آپ کے آلے کی منفرد ID (IMSI یا IMEI) کو ریکارڈ کیا۔\n\nاس کا مطلب ہے کہ آپ کا مقام، سرگرمی یا شناخت لاگ ان ہو چکی ہیں۔ یہ عام بات ہے لیکن رازداری کے بارے میں فکر مند لوگوں کے لیے ایک مسئلہ ہو سکتا ہے۔"</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> میں، آپ کے <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM استعمال کرتے ہوئے قریبی نیٹ ورک نے آپ کے آلے کی منفرد ID (IMSI یا IMEI) کو ریکارڈ کیا۔\n\nاس کا مطلب ہے کہ آپ کا مقام، سرگرمی یا شناخت کو ریکارڈ کیا جا چکا ہے۔ یہ عام بات ہے لیکن رازداری کے بارے میں فکر مند لوگوں کے لیے ایک مسئلہ ہو سکتا ہے۔"</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"مرموز کردہ نیٹ ورک <xliff:g id="NETWORK_NAME">%1$s</xliff:g> سے منسلک ہے"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM کا کنکشن اب بہت محفوظ ہے"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"غیر مرموز کردہ نیٹ ورک سے منسلک ہے"</string> @@ -644,7 +644,7 @@ <string name="biometric_or_screen_lock_dialog_default_subtitle" msgid="159539678371552009">"جاری رکھنے کے لیے اپنے بایو میٹرک اور اسکرین لاک کا استعمال کریں"</string> <string name="biometric_error_hw_unavailable" msgid="2494077380540615216">"بایومیٹرک ہارڈ ویئر دستیاب نہیں ہے"</string> <string name="biometric_error_user_canceled" msgid="6732303949695293730">"تصدیق کا عمل منسوخ ہو گیا"</string> - <string name="biometric_not_recognized" msgid="5106687642694635888">"تسلیم شدہ نہیں ہے"</string> + <string name="biometric_not_recognized" msgid="5106687642694635888">"شناخت نہیں ہو سکی"</string> <string name="biometric_face_not_recognized" msgid="5535599455744525200">"چہرے کی شناخت نہیں ہو سکی"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"تصدیق کا عمل منسوخ ہو گیا"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"کوئی پن، پیٹرن، یا پاس ورڈ سیٹ نہیں ہے"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"پیغامات ایپ کو کھولیں"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"اس کے کام کرنے کا طریقہ"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"زیر التواء..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index 4ddd368766c8..c143244db230 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Xabarlar ilovasini ochish"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Ishlash tartibi"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Kutilmoqda..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index c633c2af0a15..a0775d400d5d 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -155,15 +155,15 @@ <string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Không được chuyển tiếp"</string> <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Bảo mật mạng di động"</string> <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Mã hoá, thông báo cho mạng chưa được mã hoá"</string> - <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Mã thiết bị được truy cập"</string> + <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Mã thiết bị đã bị truy cập"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"Vào <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, một mạng lân cận đã ghi nhận mã nhận dạng duy nhất của thiết bị của bạn (IMSI hoặc IMEI) trong lúc sử dụng SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> của bạn"</string> - <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Vào <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, một mạng lân cận đã ghi nhận mã nhận dạng duy nhất của thiết bị của bạn (IMSI hoặc IMEI) trong lúc sử dụng SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> của bạn.\n\nTức là vị trí, hoạt động hoặc danh tính của bạn đã được ghi lại. Đây là một phương thức thông dụng nhưng có thể trở thành vấn đề đối với những ai lo ngại về quyền riêng tư."</string> + <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"Vào <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>, một mạng lân cận đã ghi lại mã nhận dạng duy nhất của thiết bị của bạn (IMSI hoặc IMEI) trong lúc sử dụng SIM <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> của bạn.\n\nTức là vị trí, hoạt động hoặc danh tính của bạn đã được ghi lại. Đây là một phương thức thông dụng nhưng có thể trở thành vấn đề đối với những ai lo ngại về quyền riêng tư."</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"Đã kết nối với mạng <xliff:g id="NETWORK_NAME">%1$s</xliff:g> đã mã hoá"</string> <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"Kết nối SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> nay an toàn hơn"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"Đã kết nối với mạng chưa được mã hoá"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"Cuộc gọi, tin nhắn và dữ liệu hiện dễ bị tấn công trong lúc sử dụng SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> của bạn."</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"Cuộc gọi, tin nhắn và dữ liệu hiện dễ bị tấn công trong lúc sử dụng SIM <xliff:g id="NETWORK_NAME">%1$s</xliff:g> của bạn.\n\nKhi kết nối của bạn được mã hoá lại, bạn sẽ nhận được một thông báo khác."</string> - <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Chế độ bảo mật mạng di động"</string> + <string name="scNullCipherIssueActionSettings" msgid="5888857706424639946">"Cài đặt an ninh mạng di động"</string> <string name="scNullCipherIssueActionLearnMore" msgid="7896642417214757769">"Tìm hiểu thêm"</string> <string name="scNullCipherIssueActionGotIt" msgid="8747796640866585787">"Tôi hiểu"</string> <string name="fcComplete" msgid="1080909484660507044">"Mã tính năng đã hoàn tất."</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Mở ứng dụng Tin nhắn"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Cách hoạt động"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Đang chờ xử lý..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index f16881a847c3..00dd3db2b35a 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -154,12 +154,12 @@ <string name="cfTemplateRegistered" msgid="5619930473441550596">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:无法转接"</string> <string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:无法转接"</string> <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"移动网络安全"</string> - <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"加密,连接到未加密网络时通知"</string> + <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"加密、通知(连接到未加密网络时)"</string> <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"有网络获取了设备 ID"</string> <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>,当您使用<xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM 卡时,一个附近的网络记录了您设备的唯一 ID(IMSI 或 IMEI)"</string> <string name="scIdentifierDisclosureIssueSummary" msgid="7283387338827749276">"<xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g>,当您使用<xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g> SIM 卡时,一个附近的网络记录了您设备的唯一 ID(IMSI 或 IMEI)。\n\n这意味着您的位置信息、活动或身份信息都被记录了。这是常见做法,但对注重隐私的人来说可能是一个问题。"</string> <string name="scNullCipherIssueEncryptedTitle" msgid="234717016411824969">"连接到了名为“<xliff:g id="NETWORK_NAME">%1$s</xliff:g>”的加密网络"</string> - <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM 卡连接现在更安全了"</string> + <string name="scNullCipherIssueEncryptedSummary" msgid="8577510708842150475">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM 卡的连接现在更安全了"</string> <string name="scNullCipherIssueNonEncryptedTitle" msgid="3978071464929453915">"连接到了一个未加密的网络"</string> <string name="scNullCipherIssueNonEncryptedSummaryNotification" msgid="7386936934128110388">"目前,当您使用<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM 卡时,通话、消息和数据更易受到攻击"</string> <string name="scNullCipherIssueNonEncryptedSummary" msgid="5093428974513703253">"目前,当您使用<xliff:g id="NETWORK_NAME">%1$s</xliff:g> SIM 卡时,通话、消息和数据更易受到攻击。\n\n当您的连接再次加密时,您会另收到一条通知。"</string> @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"打开“信息”应用"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"运作方式"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"待归档…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index efa260f3f4e6..142940a86ebb 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"開啟「訊息」"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"運作方式"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"待處理…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 0c18193fc542..b7ee23c23f21 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -2144,10 +2144,8 @@ <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"日常安排模式資訊通知"</string> <string name="dynamic_mode_notification_title" msgid="1388718452788985481">"已開啟省電模式"</string> <string name="dynamic_mode_notification_summary" msgid="1639031262484979689">"降低電池用量,以便延長電池續航力"</string> - <!-- no translation found for dynamic_mode_notification_title_v2 (5072385242078021152) --> - <skip /> - <!-- no translation found for dynamic_mode_notification_summary_v2 (2142444344663147938) --> - <skip /> + <string name="dynamic_mode_notification_title_v2" msgid="5072385242078021152">"省電模式已開啟"</string> + <string name="dynamic_mode_notification_summary_v2" msgid="2142444344663147938">"已開啟省電模式,延長電池續航力"</string> <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"省電模式"</string> <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"省電模式已關閉"</string> <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"手機電力充足,各項功能不再受到限制。"</string> @@ -2415,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"開啟「訊息」應用程式"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"運作方式"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"待處理…"</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 7dc3fd63719e..a967fb6f1ad1 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -2413,4 +2413,22 @@ <string name="satellite_notification_open_message" msgid="4149234979688273729">"Vula Imilayezo"</string> <string name="satellite_notification_how_it_works" msgid="3132069321977520519">"Indlela esebenza ngayo"</string> <string name="unarchival_session_app_label" msgid="6811856981546348205">"Ilindile..."</string> + <!-- no translation found for fingerprint_dangling_notification_title (7362075195588639989) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_1 (6261149111900787302) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_2 (7688302770424064884) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_1 (2927018569542316055) --> + <skip /> + <!-- no translation found for fingerprint_dangling_notification_msg_all_deleted_2 (6897989352716156176) --> + <skip /> + <!-- no translation found for face_dangling_notification_title (947852541060975473) --> + <skip /> + <!-- no translation found for face_dangling_notification_msg (8806849376915541655) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_set_up (8246885009807817961) --> + <skip /> + <!-- no translation found for biometric_dangling_notification_action_not_now (8095249216864443491) --> + <skip /> </resources> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 37d39a752c65..5fa13bab7b0c 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1346,6 +1346,51 @@ <attr name="materialColorTertiary" format="color"/> <!-- The error color for the app, intended to draw attention to error conditions. @hide --> <attr name="materialColorError" format="color"/> + + <!-- System Custom Tokens--> + <!-- @hide --> + <attr name="customColorWidgetBackground" format="color"/> + <!-- @hide --> + <attr name="customColorClockHour" format="color"/> + <!-- @hide --> + <attr name="customColorClockMinute" format="color"/> + <!-- @hide --> + <attr name="customColorClockSecond" format="color"/> + <!-- @hide --> + <attr name="customColorThemeApp" format="color"/> + <!-- @hide --> + <attr name="customColorOnThemeApp" format="color"/> + <!-- @hide --> + <attr name="customColorThemeAppRing" format="color"/> + <!-- @hide --> + <attr name="customColorOnThemeAppRing" format="color"/> + <!-- @hide --> + <attr name="customColorBrandA" format="color"/> + <!-- @hide --> + <attr name="customColorBrandB" format="color"/> + <!-- @hide --> + <attr name="customColorBrandC" format="color"/> + <!-- @hide --> + <attr name="customColorBrandD" format="color"/> + <!-- @hide --> + <attr name="customColorUnderSurface" format="color"/> + <!-- @hide --> + <attr name="customColorShadeActive" format="color"/> + <!-- @hide --> + <attr name="customColorOnShadeActive" format="color"/> + <!-- @hide --> + <attr name="customColorOnShadeActiveVariant" format="color"/> + <!-- @hide --> + <attr name="customColorShadeInactive" format="color"/> + <!-- @hide --> + <attr name="customColorOnShadeInactive" format="color"/> + <!-- @hide --> + <attr name="customColorOnShadeInactiveVariant" format="color"/> + <!-- @hide --> + <attr name="customColorShadeDisabled" format="color"/> + <!-- @hide --> + <attr name="customColorOverviewBackground" format="color"/> + </declare-styleable> <!-- **************************************************************** --> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index e6719195565e..5e039b5e958d 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -581,6 +581,51 @@ <color name="system_on_tertiary_fixed">#FFFFFF</color> <color name="system_on_tertiary_fixed_variant">#FFFFFF</color> + <!--Colors used in Android system, from design system. These values can be overlaid at runtime + by OverlayManager RROs.--> + <color name="system_widget_background_light">#EEF0FF</color> + <color name="system_clock_hour_light">#1D2435</color> + <color name="system_clock_minute_light">#20386A</color> + <color name="system_clock_second_light">#000000</color> + <color name="system_theme_app_light">#2F4578</color> + <color name="system_on_theme_app_light">#D6DFFF</color> + <color name="system_theme_app_ring_light">#94AAE4</color> + <color name="system_on_theme_app_ring_light">#FDD7FA</color> + <color name="system_brand_a_light">#3A5084</color> + <color name="system_brand_b_light">#6E7488</color> + <color name="system_brand_c_light">#6076AC</color> + <color name="system_brand_d_light">#8C6D8C</color> + <color name="system_under_surface_light">#000000</color> + <color name="system_shade_active_light">#D9E2FF</color> + <color name="system_on_shade_active_light">#152E60</color> + <color name="system_on_shade_active_variant_light">#2F4578</color> + <color name="system_shade_inactive_light">#2F3036</color> + <color name="system_on_shade_inactive_light">#E1E2EC</color> + <color name="system_on_shade_inactive_variant_light">#C5C6D0</color> + <color name="system_shade_disabled_light">#0C0E13</color> + <color name="system_overview_background_light">#50525A</color> + <color name="system_widget_background_dark">#152E60</color> + <color name="system_clock_hour_dark">#9AA0B6</color> + <color name="system_clock_minute_dark">#D8E1FF</color> + <color name="system_clock_second_dark">#FFFFFF</color> + <color name="system_theme_app_dark">#D9E2FF</color> + <color name="system_on_theme_app_dark">#304679</color> + <color name="system_theme_app_ring_dark">#94AAE4</color> + <color name="system_on_theme_app_ring_dark">#E0BBDD</color> + <color name="system_brand_a_dark">#90A6DF</color> + <color name="system_brand_b_dark">#A4ABC1</color> + <color name="system_brand_c_dark">#7A90C8</color> + <color name="system_brand_d_dark">#A886A6</color> + <color name="system_under_surface_dark">#000000</color> + <color name="system_shade_active_dark">#D9E2FF</color> + <color name="system_on_shade_active_dark">#001945</color> + <color name="system_on_shade_active_variant_dark">#2F4578</color> + <color name="system_shade_inactive_dark">#2F3036</color> + <color name="system_on_shade_inactive_dark">#E1E2EC</color> + <color name="system_on_shade_inactive_variant_dark">#C5C6D0</color> + <color name="system_shade_disabled_dark">#0C0E13</color> + <color name="system_overview_background_dark">#C5C6D0</color> + <!-- Accessibility shortcut icon background color --> <color name="accessibility_feature_background">#5F6368</color> <!-- Google grey 700 --> <color name="accessibility_magnification_background">#F50D60</color> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index cefc648e45a5..5bd20332f381 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4444,8 +4444,8 @@ <!-- True if camera app should be pinned via Pinner Service --> <bool name="config_pinnerCameraApp">false</bool> - <!-- True if home app should be pinned via Pinner Service --> - <bool name="config_pinnerHomeApp">false</bool> + <!-- Bytes that the PinnerService will pin for Home app --> + <integer name="config_pinnerHomePinBytes">0</integer> <!-- True if assistant app should be pinned via Pinner Service --> <bool name="config_pinnerAssistantApp">false</bool> @@ -4652,6 +4652,19 @@ --> <string-array name="config_companionDeviceCerts" translatable="false"></string-array> + <!-- A list of packages that auto-enable permissions sync feature. + Note that config_companionPermSyncEnabledPackages and config_companionPermSyncEnabledCerts + are parallel arrays. + --> + <string-array name="config_companionPermSyncEnabledPackages" translatable="false"></string-array> + + <!-- A list of SHA256 Certificates corresponding to config_companionPermSyncEnabledPackages. + Note that config_companionPermSyncEnabledPackages and config_companionPermSyncEnabledCerts + are parallel arrays. + Example: "1A:2B:3C:4D" + --> + <string-array name="config_companionPermSyncEnabledCerts" translatable="false"></string-array> + <!-- The package name for the default wellbeing app. This package must be trusted, as it has the permissions to control other applications on the device. @@ -4704,6 +4717,13 @@ <!-- The component name for the default system on-device sandboxed inference service. --> <string name="config_defaultOnDeviceSandboxedInferenceService" translatable="false"></string> + <!-- The broadcast intent name for notifying when the on-device model is loading --> + <string name="config_onDeviceIntelligenceModelLoadedBroadcastKey" translatable="false"></string> + + <!-- The broadcast intent name for notifying when the on-device model has been unloaded --> + <string name="config_onDeviceIntelligenceModelUnloadedBroadcastKey" translatable="false"></string> + + <!-- Component name that accepts ACTION_SEND intents for requesting ambient context consent for wearable sensing. --> <string translatable="false" name="config_defaultWearableSensingConsentComponent"></string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d058fb188d16..d004b050fae8 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -675,6 +675,8 @@ <java-symbol type="string" name="config_companionDeviceManagerPackage" /> <java-symbol type="array" name="config_companionDevicePackages" /> <java-symbol type="array" name="config_companionDeviceCerts" /> + <java-symbol type="array" name="config_companionPermSyncEnabledPackages" /> + <java-symbol type="array" name="config_companionPermSyncEnabledCerts" /> <java-symbol type="string" name="config_default_dns_server" /> <java-symbol type="string" name="config_ethernet_iface_regex" /> <java-symbol type="string" name="not_checked" /> @@ -3437,7 +3439,7 @@ <!-- Pinner Service --> <java-symbol type="array" name="config_defaultPinnerServiceFiles" /> <java-symbol type="bool" name="config_pinnerCameraApp" /> - <java-symbol type="bool" name="config_pinnerHomeApp" /> + <java-symbol type="integer" name="config_pinnerHomePinBytes" /> <java-symbol type="bool" name="config_pinnerAssistantApp" /> <java-symbol type="integer" name="config_pinnerWebviewPinBytes" /> @@ -3941,6 +3943,8 @@ <java-symbol type="string" name="config_defaultWearableSensingService" /> <java-symbol type="string" name="config_defaultOnDeviceIntelligenceService" /> <java-symbol type="string" name="config_defaultOnDeviceSandboxedInferenceService" /> + <java-symbol type="string" name="config_onDeviceIntelligenceModelLoadedBroadcastKey" /> + <java-symbol type="string" name="config_onDeviceIntelligenceModelUnloadedBroadcastKey" /> <java-symbol type="string" name="config_retailDemoPackage" /> <java-symbol type="string" name="config_retailDemoPackageSignature" /> @@ -5288,6 +5292,71 @@ <java-symbol name="materialColorTertiary" type="attr"/> <java-symbol name="materialColorError" type="attr"/> + <java-symbol name="customColorWidgetBackground" type="attr"/> + <java-symbol name="customColorClockHour" type="attr"/> + <java-symbol name="customColorClockMinute" type="attr"/> + <java-symbol name="customColorClockSecond" type="attr"/> + <java-symbol name="customColorThemeApp" type="attr"/> + <java-symbol name="customColorOnThemeApp" type="attr"/> + <java-symbol name="customColorThemeAppRing" type="attr"/> + <java-symbol name="customColorOnThemeAppRing" type="attr"/> + <java-symbol name="customColorBrandA" type="attr"/> + <java-symbol name="customColorBrandB" type="attr"/> + <java-symbol name="customColorBrandC" type="attr"/> + <java-symbol name="customColorBrandD" type="attr"/> + <java-symbol name="customColorUnderSurface" type="attr"/> + <java-symbol name="customColorShadeActive" type="attr"/> + <java-symbol name="customColorOnShadeActive" type="attr"/> + <java-symbol name="customColorOnShadeActiveVariant" type="attr"/> + <java-symbol name="customColorShadeInactive" type="attr"/> + <java-symbol name="customColorOnShadeInactive" type="attr"/> + <java-symbol name="customColorOnShadeInactiveVariant" type="attr"/> + <java-symbol name="customColorShadeDisabled" type="attr"/> + <java-symbol name="customColorOverviewBackground" type="attr"/> + + <java-symbol name="system_widget_background_light" type="color"/> + <java-symbol name="system_clock_hour_light" type="color"/> + <java-symbol name="system_clock_minute_light" type="color"/> + <java-symbol name="system_clock_second_light" type="color"/> + <java-symbol name="system_theme_app_light" type="color"/> + <java-symbol name="system_on_theme_app_light" type="color"/> + <java-symbol name="system_theme_app_ring_light" type="color"/> + <java-symbol name="system_on_theme_app_ring_light" type="color"/> + <java-symbol name="system_brand_a_light" type="color"/> + <java-symbol name="system_brand_b_light" type="color"/> + <java-symbol name="system_brand_c_light" type="color"/> + <java-symbol name="system_brand_d_light" type="color"/> + <java-symbol name="system_under_surface_light" type="color"/> + <java-symbol name="system_shade_active_light" type="color"/> + <java-symbol name="system_on_shade_active_light" type="color"/> + <java-symbol name="system_on_shade_active_variant_light" type="color"/> + <java-symbol name="system_shade_inactive_light" type="color"/> + <java-symbol name="system_on_shade_inactive_light" type="color"/> + <java-symbol name="system_on_shade_inactive_variant_light" type="color"/> + <java-symbol name="system_shade_disabled_light" type="color"/> + <java-symbol name="system_overview_background_light" type="color"/> + <java-symbol name="system_widget_background_dark" type="color"/> + <java-symbol name="system_clock_hour_dark" type="color"/> + <java-symbol name="system_clock_minute_dark" type="color"/> + <java-symbol name="system_clock_second_dark" type="color"/> + <java-symbol name="system_theme_app_dark" type="color"/> + <java-symbol name="system_on_theme_app_dark" type="color"/> + <java-symbol name="system_theme_app_ring_dark" type="color"/> + <java-symbol name="system_on_theme_app_ring_dark" type="color"/> + <java-symbol name="system_brand_a_dark" type="color"/> + <java-symbol name="system_brand_b_dark" type="color"/> + <java-symbol name="system_brand_c_dark" type="color"/> + <java-symbol name="system_brand_d_dark" type="color"/> + <java-symbol name="system_under_surface_dark" type="color"/> + <java-symbol name="system_shade_active_dark" type="color"/> + <java-symbol name="system_on_shade_active_dark" type="color"/> + <java-symbol name="system_on_shade_active_variant_dark" type="color"/> + <java-symbol name="system_shade_inactive_dark" type="color"/> + <java-symbol name="system_on_shade_inactive_dark" type="color"/> + <java-symbol name="system_on_shade_inactive_variant_dark" type="color"/> + <java-symbol name="system_shade_disabled_dark" type="color"/> + <java-symbol name="system_overview_background_dark" type="color"/> + <java-symbol type="attr" name="actionModeUndoDrawable" /> <java-symbol type="attr" name="actionModeRedoDrawable" /> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index ee191449ac35..24d493867906 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -284,6 +284,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" /> @@ -380,6 +402,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme @@ -475,6 +519,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and @@ -572,6 +638,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent @@ -668,6 +756,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be @@ -772,6 +882,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a @@ -867,6 +999,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar --> @@ -961,6 +1115,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width @@ -1056,6 +1232,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. --> @@ -1167,6 +1365,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- DeviceDefault theme for a window without an action bar that will be displayed either @@ -1263,6 +1483,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- DeviceDefault theme for a presentation window on a secondary display. --> @@ -1357,6 +1599,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- DeviceDefault theme for panel windows. This removes all extraneous window @@ -1453,6 +1717,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear @@ -1548,6 +1834,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear @@ -1643,6 +1951,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- DeviceDefault style for input methods, which is used by the @@ -1738,6 +2068,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- DeviceDefault style for input methods, which is used by the @@ -1833,6 +2185,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert"> @@ -1928,6 +2302,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- Theme for the dialog shown when an app crashes or ANRs. --> @@ -2028,6 +2424,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame"> @@ -2121,6 +2539,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style --> @@ -2352,6 +2792,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an @@ -2447,6 +2909,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar --> @@ -2541,6 +3025,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar. @@ -2636,6 +3142,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar @@ -2733,6 +3261,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent @@ -2829,6 +3379,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be @@ -2931,6 +3503,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a @@ -3029,6 +3623,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar --> @@ -3126,6 +3742,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum @@ -3224,6 +3862,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. --> @@ -3303,6 +3963,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. --> @@ -3382,6 +4064,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller @@ -3480,6 +4184,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- DeviceDefault light theme for a window without an action bar that will be displayed either @@ -3579,6 +4305,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- DeviceDefault light theme for a presentation window on a secondary display. --> @@ -3676,6 +4424,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- DeviceDefault light theme for panel windows. This removes all extraneous window @@ -3772,6 +4542,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert"> @@ -3867,6 +4659,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <style name="Theme.DeviceDefault.Dialog.Alert.DayNight" parent="Theme.DeviceDefault.Light.Dialog.Alert" /> @@ -3962,6 +4776,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice"> @@ -4055,6 +4891,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- DeviceDefault theme for a window that should look like the Settings app. --> @@ -4156,6 +5014,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <style name="Theme.DeviceDefault.SystemUI" parent="Theme.DeviceDefault.Light"> @@ -4238,6 +5118,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <style name="Theme.DeviceDefault.SystemUI.Dialog" parent="Theme.DeviceDefault.Light.Dialog"> @@ -4312,6 +5214,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar --> @@ -4407,6 +5331,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <style name="Theme.DeviceDefault.Settings.DialogBase" parent="Theme.Material.Light.BaseDialog"> @@ -4486,6 +5432,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Settings.DialogBase"> @@ -4605,6 +5573,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert"> @@ -4702,6 +5692,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" /> @@ -4825,6 +5837,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <style name="ThemeOverlay.DeviceDefault.Accent.Light"> @@ -4878,6 +5912,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <!-- Theme overlay that replaces colorAccent with the colorAccent from {@link #Theme_DeviceDefault_DayNight}. --> @@ -4935,6 +5991,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <style name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" parent="Theme.DeviceDefault.NoActionBar.Fullscreen"> @@ -4988,6 +6066,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_light</item> <item name="materialColorTertiary">@color/system_tertiary_light</item> <item name="materialColorError">@color/system_error_light</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> + <item name="customColorClockHour">@color/system_clock_hour_light</item> + <item name="customColorClockMinute">@color/system_clock_minute_light</item> + <item name="customColorClockSecond">@color/system_clock_second_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_light</item> + <item name="customColorBrandA">@color/system_brand_a_light</item> + <item name="customColorBrandB">@color/system_brand_b_light</item> + <item name="customColorBrandC">@color/system_brand_c_light</item> + <item name="customColorBrandD">@color/system_brand_d_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_light</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorOverviewBackground">@color/system_overview_background_light</item> </style> <style name="Theme.DeviceDefault.Notification" parent="@style/Theme.Material.Notification"> @@ -5052,6 +6152,28 @@ easier. <item name="materialColorSecondary">@color/system_secondary_dark</item> <item name="materialColorTertiary">@color/system_tertiary_dark</item> <item name="materialColorError">@color/system_error_dark</item> + + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> + <item name="customColorClockHour">@color/system_clock_hour_dark</item> + <item name="customColorClockMinute">@color/system_clock_minute_dark</item> + <item name="customColorClockSecond">@color/system_clock_second_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorOnThemeApp">@color/system_on_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorOnThemeAppRing">@color/system_on_theme_app_ring_dark</item> + <item name="customColorBrandA">@color/system_brand_a_dark</item> + <item name="customColorBrandB">@color/system_brand_b_dark</item> + <item name="customColorBrandC">@color/system_brand_c_dark</item> + <item name="customColorBrandD">@color/system_brand_d_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorOnShadeActive">@color/system_on_shade_active_dark</item> + <item name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</item> + <item name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> </style> <style name="Theme.DeviceDefault.AutofillHalfScreenDialogList" parent="Theme.DeviceDefault.DayNight"> <item name="colorListDivider">@color/list_divider_opacity_device_default_light</item> diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java index 7fb894a9dbe9..30ec940bda8e 100644 --- a/core/tests/coretests/src/android/app/NotificationTest.java +++ b/core/tests/coretests/src/android/app/NotificationTest.java @@ -84,7 +84,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.os.SystemProperties; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.text.Spannable; @@ -132,9 +131,6 @@ public class NotificationTest { @Before public void setUp() { mContext = InstrumentationRegistry.getContext(); - // TODO(b/169435530): remove this flag set once resolved. - SystemProperties.set("persist.sysui.notification.builder_extras_override", - Boolean.toString(false)); } @Test @@ -1703,10 +1699,6 @@ public class NotificationTest { // Ensures that extras in a Notification Builder can be updated. @Test public void testExtras_cachedExtrasOverwrittenByUserProvided() { - // Sets the flag to new state. - // TODO(b/169435530): remove this set value once resolved. - SystemProperties.set("persist.sysui.notification.builder_extras_override", - Boolean.toString(true)); Bundle extras = new Bundle(); extras.putCharSequence(EXTRA_TITLE, "test title"); extras.putCharSequence(EXTRA_SUMMARY_TEXT, "summary text"); @@ -1732,10 +1724,6 @@ public class NotificationTest { // Ensures that extras in a Notification Builder can be updated by an extender. @Test public void testExtras_cachedExtrasOverwrittenByExtender() { - // Sets the flag to new state. - // TODO(b/169435530): remove this set value once resolved. - SystemProperties.set("persist.sysui.notification.builder_extras_override", - Boolean.toString(true)); Notification.CarExtender extender = new Notification.CarExtender().setColor(1234); Notification notification = new Notification.Builder(mContext, "test id") @@ -1749,58 +1737,6 @@ public class NotificationTest { assertThat(recoveredExtender.getColor()).isEqualTo(5678); } - // Validates pre-flag flip behavior, that extras in a Notification Builder cannot be updated. - // TODO(b/169435530): remove this test once resolved. - @Test - public void testExtras_cachedExtrasOverwrittenByUserProvidedOld() { - // Sets the flag to old state. - SystemProperties.set("persist.sysui.notification.builder_extras_override", - Boolean.toString(false)); - - Bundle extras = new Bundle(); - extras.putCharSequence(EXTRA_TITLE, "test title"); - extras.putCharSequence(EXTRA_SUMMARY_TEXT, "summary text"); - - Notification.Builder builder = new Notification.Builder(mContext, "test id") - .addExtras(extras); - - Notification notification = builder.build(); - assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo( - "test title"); - assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo( - "summary text"); - - extras.putCharSequence(EXTRA_TITLE, "new title"); - builder.addExtras(extras); - notification = builder.build(); - assertThat(notification.extras.getCharSequence(EXTRA_TITLE).toString()).isEqualTo( - "test title"); - assertThat(notification.extras.getCharSequence(EXTRA_SUMMARY_TEXT).toString()).isEqualTo( - "summary text"); - } - - // Validates pre-flag flip behavior, that extras in a Notification Builder cannot be updated - // by an extender. - // TODO(b/169435530): remove this test once resolved. - @Test - public void testExtras_cachedExtrasOverwrittenByExtenderOld() { - // Sets the flag to old state. - SystemProperties.set("persist.sysui.notification.builder_extras_override", - Boolean.toString(false)); - - Notification.CarExtender extender = new Notification.CarExtender().setColor(1234); - - Notification notification = new Notification.Builder(mContext, "test id") - .extend(extender).build(); - - extender.setColor(5678); - - Notification.Builder.recoverBuilder(mContext, notification).extend(extender).build(); - - Notification.CarExtender recoveredExtender = new Notification.CarExtender(notification); - assertThat(recoveredExtender.getColor()).isEqualTo(1234); - } - @Test @CoreCompatChangeRule.EnableCompatChanges({Notification.WEARABLE_EXTENDER_BACKGROUND_BLOCKED}) public void wearableBackgroundBlockEnabled_wearableBackgroundSet_valueRemainsNull() { diff --git a/core/tests/coretests/src/android/graphics/drawable/IconTest.java b/core/tests/coretests/src/android/graphics/drawable/IconTest.java index 950925f488fd..e0c3b0451a8b 100644 --- a/core/tests/coretests/src/android/graphics/drawable/IconTest.java +++ b/core/tests/coretests/src/android/graphics/drawable/IconTest.java @@ -475,8 +475,8 @@ public class IconTest { final Icon ic = Icon.createWithBitmap(bm); final Drawable drawable = ic.loadDrawable(mContext); - assertThat(drawable.getIntrinsicWidth()).isEqualTo(maxWidth); - assertThat(drawable.getIntrinsicHeight()).isEqualTo(maxHeight); + assertThat(Math.abs(drawable.getIntrinsicWidth() - maxWidth)).isLessThan(2); + assertThat(Math.abs(drawable.getIntrinsicHeight() - maxHeight)).isLessThan(2); } @Test diff --git a/core/tests/coretests/src/android/net/OWNERS b/core/tests/coretests/src/android/net/OWNERS index a779c00814cb..beb77dc8f4fd 100644 --- a/core/tests/coretests/src/android/net/OWNERS +++ b/core/tests/coretests/src/android/net/OWNERS @@ -1,4 +1,5 @@ include /services/core/java/com/android/server/net/OWNERS -per-file SSL*,Uri*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com +per-file SSL*,Url* = prb@google.com,oth@google.com,narayan@google.com,ngeoffray@google.com per-file SntpClient* = file:/services/core/java/com/android/server/timedetector/OWNERS +per-file Uri* = varunshah@google.com diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java index 6793fa549ef0..e93b0bf1e69a 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/DividerPresenter.java @@ -466,10 +466,6 @@ class DividerPresenter implements View.OnTouchListener { } if (dividerAttributes.getDividerType() == DividerAttributes.DIVIDER_TYPE_DRAGGABLE) { - // Draggable divider width must be larger than the drag handle size. - widthDp = Math.max(widthDp, - getDimensionDp(R.dimen.activity_embedding_divider_touch_target_width)); - // Update minRatio and maxRatio only when it is a draggable divider. if (minRatio == RATIO_SYSTEM_DEFAULT) { minRatio = DEFAULT_MIN_RATIO; @@ -912,17 +908,21 @@ class DividerPresenter implements View.OnTouchListener { @NonNull private final FrameLayout mDividerLayout; @NonNull + private final View mDividerLine; + private View mDragHandle; + @NonNull private final View.OnTouchListener mListener; @NonNull private Properties mProperties; private int mDividerWidthPx; + private int mHandleWidthPx; @Nullable private SurfaceControl mPrimaryVeil; @Nullable private SurfaceControl mSecondaryVeil; private boolean mIsDragging; private int mDividerPosition; - private View mDragHandle; + private int mDividerSurfaceWidthPx; private Renderer(@NonNull Properties properties, @NonNull View.OnTouchListener listener) { mProperties = properties; @@ -940,6 +940,7 @@ class DividerPresenter implements View.OnTouchListener { context, displayManager.getDisplay(mProperties.mDisplayId), mWindowlessWindowManager, "DividerContainer"); mDividerLayout = new FrameLayout(context); + mDividerLine = new View(context); update(); } @@ -956,6 +957,17 @@ class DividerPresenter implements View.OnTouchListener { mDividerWidthPx = getDividerWidthPx(mProperties.mDividerAttributes); mDividerPosition = mProperties.mInitialDividerPosition; mWindowlessWindowManager.setConfiguration(mProperties.mConfiguration); + + if (mProperties.mDividerAttributes.getDividerType() + == DividerAttributes.DIVIDER_TYPE_DRAGGABLE) { + // TODO(b/329193115) support divider on secondary display + final Context context = ActivityThread.currentActivityThread().getApplication(); + mHandleWidthPx = context.getResources().getDimensionPixelSize( + R.dimen.activity_embedding_divider_touch_target_width); + } else { + mHandleWidthPx = 0; + } + // TODO handle synchronization between surface transactions and WCT. final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); updateSurface(t); @@ -985,13 +997,45 @@ class DividerPresenter implements View.OnTouchListener { */ private void updateSurface(@NonNull SurfaceControl.Transaction t) { final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds(); + + int dividerSurfacePosition; + if (mProperties.mDividerAttributes.getDividerType() + == DividerAttributes.DIVIDER_TYPE_DRAGGABLE) { + // When the divider drag handle width is larger than the divider width, the position + // of the divider surface is adjusted so that it is large enough to host both the + // divider line and the divider drag handle. + mDividerSurfaceWidthPx = Math.max(mDividerWidthPx, mHandleWidthPx); + dividerSurfacePosition = + mProperties.mIsReversedLayout + ? mDividerPosition + : mDividerPosition + mDividerWidthPx - mDividerSurfaceWidthPx; + dividerSurfacePosition = Math.clamp(dividerSurfacePosition, 0, + mProperties.mIsVerticalSplit ? taskBounds.width() : taskBounds.height()); + } else { + mDividerSurfaceWidthPx = mDividerWidthPx; + dividerSurfacePosition = mDividerPosition; + } + if (mProperties.mIsVerticalSplit) { - t.setPosition(mDividerSurface, mDividerPosition, 0.0f); - t.setWindowCrop(mDividerSurface, mDividerWidthPx, taskBounds.height()); + t.setPosition(mDividerSurface, dividerSurfacePosition, 0.0f); + t.setWindowCrop(mDividerSurface, mDividerSurfaceWidthPx, taskBounds.height()); } else { - t.setPosition(mDividerSurface, 0.0f, mDividerPosition); - t.setWindowCrop(mDividerSurface, taskBounds.width(), mDividerWidthPx); + t.setPosition(mDividerSurface, 0.0f, dividerSurfacePosition); + t.setWindowCrop(mDividerSurface, taskBounds.width(), mDividerSurfaceWidthPx); } + + // Update divider line position in the surface + if (!mProperties.mIsReversedLayout) { + final int offset = mDividerPosition - dividerSurfacePosition; + mDividerLine.setX(mProperties.mIsVerticalSplit ? offset : 0); + mDividerLine.setY(mProperties.mIsVerticalSplit ? 0 : offset); + } else { + // For reversed layout, the divider line is always at the start of the divider + // surface. + mDividerLine.setX(0); + mDividerLine.setY(0); + } + if (mIsDragging) { updateVeils(t); } @@ -1006,14 +1050,14 @@ class DividerPresenter implements View.OnTouchListener { final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds(); final WindowManager.LayoutParams lp = mProperties.mIsVerticalSplit ? new WindowManager.LayoutParams( - mDividerWidthPx, + mDividerSurfaceWidthPx, taskBounds.height(), TYPE_APPLICATION_PANEL, FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_SLIPPERY, PixelFormat.TRANSLUCENT) : new WindowManager.LayoutParams( taskBounds.width(), - mDividerWidthPx, + mDividerSurfaceWidthPx, TYPE_APPLICATION_PANEL, FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL | FLAG_SLIPPERY, PixelFormat.TRANSLUCENT); @@ -1030,12 +1074,19 @@ class DividerPresenter implements View.OnTouchListener { */ private void updateDivider(@NonNull SurfaceControl.Transaction t) { mDividerLayout.removeAllViews(); - if (mProperties.mIsDraggableExpandType) { + mDividerLayout.addView(mDividerLine); + if (mProperties.mIsDraggableExpandType && !mIsDragging) { // If a container is fully expanded, the divider overlays on the expanded container. - mDividerLayout.setBackgroundColor(Color.TRANSPARENT); + mDividerLine.setBackgroundColor(Color.TRANSPARENT); } else { - mDividerLayout.setBackgroundColor(mProperties.mDividerAttributes.getDividerColor()); + mDividerLine.setBackgroundColor(mProperties.mDividerAttributes.getDividerColor()); } + final Rect taskBounds = mProperties.mConfiguration.windowConfiguration.getBounds(); + mDividerLine.setLayoutParams( + mProperties.mIsVerticalSplit + ? new FrameLayout.LayoutParams(mDividerWidthPx, taskBounds.height()) + : new FrameLayout.LayoutParams(taskBounds.width(), mDividerWidthPx) + ); if (mProperties.mDividerAttributes.getDividerType() == DividerAttributes.DIVIDER_TYPE_DRAGGABLE) { createVeils(); @@ -1062,7 +1113,7 @@ class DividerPresenter implements View.OnTouchListener { R.dimen.activity_embedding_divider_touch_target_width)); params.gravity = Gravity.CENTER; button.setLayoutParams(params); - button.setBackgroundColor(R.color.transparent); + button.setBackgroundColor(Color.TRANSPARENT); final Drawable handle = context.getResources().getDrawable( R.drawable.activity_embedding_divider_handle, context.getTheme()); diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml index 3aecf5f53cf0..3492f136c4f9 100644 --- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml @@ -62,9 +62,9 @@ <string name="bubble_content_description_single" msgid="8495748092720065813">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string> <string name="bubble_content_description_stack" msgid="8071515017164630429">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%3$d</xliff:g> autres"</string> <string name="bubble_accessibility_action_move_top_left" msgid="2644118920500782758">"Déplacer dans coin sup. gauche"</string> - <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Déplacer dans coin sup. droit"</string> - <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Déplacer dans coin inf. gauche"</string> - <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Déplacer dans coin inf. droit"</string> + <string name="bubble_accessibility_action_move_top_right" msgid="5864594920870245525">"Déplacer en haut à droite"</string> + <string name="bubble_accessibility_action_move_bottom_left" msgid="850271002773745634">"Déplacer en bas à gauche"</string> + <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Déplacer en bas à droite"</string> <string name="bubble_accessibility_announce_expand" msgid="5388792092888203776">"développer <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string> <string name="bubble_accessibility_announce_collapse" msgid="3178806224494537097">"réduire <xliff:g id="BUBBLE_TITLE">%1$s</xliff:g>"</string> <string name="bubbles_app_settings" msgid="3617224938701566416">"Paramètres <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string> diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml index 7b7779d85d78..302c0071a73a 100644 --- a/libs/WindowManager/Shell/res/values-ky/strings.xml +++ b/libs/WindowManager/Shell/res/values-ky/strings.xml @@ -71,7 +71,7 @@ <string name="bubble_dismiss_text" msgid="8816558050659478158">"Калкып чыкма билдирмени жабуу"</string> <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Жазышууда калкып чыкма билдирмелер көрүнбөсүн"</string> <string name="bubbles_user_education_title" msgid="2112319053732691899">"Калкып чыкма билдирмелер аркылуу маектешүү"</string> - <string name="bubbles_user_education_description" msgid="4215862563054175407">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер түрүндө көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string> + <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> diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml index 4a9fab92f11f..5e43506ab621 100644 --- a/libs/WindowManager/Shell/res/values-mn/strings.xml +++ b/libs/WindowManager/Shell/res/values-mn/strings.xml @@ -53,7 +53,7 @@ <string name="accessibility_split_top" msgid="2789329702027147146">"Дээд талд хуваах"</string> <string name="accessibility_split_bottom" msgid="8694551025220868191">"Доод талд хуваах"</string> <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Нэг гарын горимыг ашиглаж байна"</string> - <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Гарахын тулд дэлгэцийн доод хэсгээс дээш шударч эсвэл апп дээр хүссэн газраа товшино уу"</string> + <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Гарахын тулд дэлгэцийн доод хэсгээс дээш шударч эсвэл аппын дээр хүссэн газраа товшино уу"</string> <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Нэг гарын горимыг эхлүүлэх"</string> <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Нэг гарын горимоос гарах"</string> <string name="bubbles_settings_button_description" msgid="1301286017420516912">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н бөмбөлгүүдийн тохиргоо"</string> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt index 037b1ec9247c..c988c2fb5103 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityBackAnimation.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 The Android Open Source Project + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.wm.shell.back import android.animation.Animator @@ -34,6 +35,7 @@ import android.view.RemoteAnimationTarget import android.view.SurfaceControl import android.view.animation.DecelerateInterpolator import android.view.animation.Interpolator +import android.view.animation.Transformation import android.window.BackEvent import android.window.BackMotionEvent import android.window.BackNavigationInfo @@ -46,52 +48,45 @@ import com.android.wm.shell.R import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.animation.Interpolators import com.android.wm.shell.protolog.ShellProtoLogGroup -import com.android.wm.shell.shared.annotations.ShellMainThread -import javax.inject.Inject import kotlin.math.abs import kotlin.math.max import kotlin.math.min -/** Class that defines cross-activity animation. */ -@ShellMainThread -class CrossActivityBackAnimation @Inject constructor( +abstract class CrossActivityBackAnimation( private val context: Context, private val background: BackAnimationBackground, - private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer + private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, + protected val transaction: SurfaceControl.Transaction, + private val choreographer: Choreographer ) : ShellBackAnimation() { - private val startClosingRect = RectF() - private val targetClosingRect = RectF() - private val currentClosingRect = RectF() + protected val startClosingRect = RectF() + protected val targetClosingRect = RectF() + protected val currentClosingRect = RectF() - private val startEnteringRect = RectF() - private val targetEnteringRect = RectF() - private val currentEnteringRect = RectF() + protected val startEnteringRect = RectF() + protected val targetEnteringRect = RectF() + protected val currentEnteringRect = RectF() - private val backAnimRect = Rect() + protected val backAnimRect = Rect() private val cropRect = Rect() private var cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) - private val backAnimationRunner = BackAnimationRunner( - Callback(), Runner(), context, Cuj.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY - ) + private val backAnimationRunner = + BackAnimationRunner(Callback(), Runner(), context, Cuj.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY) private val initialTouchPos = PointF() private val transformMatrix = Matrix() private val tmpFloat9 = FloatArray(9) - private var enteringTarget: RemoteAnimationTarget? = null - private var closingTarget: RemoteAnimationTarget? = null - private val transaction = SurfaceControl.Transaction() + protected var enteringTarget: RemoteAnimationTarget? = null + protected var closingTarget: RemoteAnimationTarget? = null private var triggerBack = false private var finishCallback: IRemoteAnimationFinishedCallback? = null private val progressAnimator = BackProgressAnimator() private val displayBoundsMargin = context.resources.getDimension(R.dimen.cross_task_back_vertical_margin) - private val enteringStartOffset = - context.resources.getDimension(R.dimen.cross_activity_back_entering_start_offset) private val gestureInterpolator = Interpolators.BACK_GESTURE - private val postCommitInterpolator = Interpolators.FAST_OUT_SLOW_IN private val verticalMoveInterpolator: Interpolator = DecelerateInterpolator() private var scrimLayer: SurfaceControl? = null @@ -103,13 +98,42 @@ class CrossActivityBackAnimation @Inject constructor( private var rightLetterboxLayer: SurfaceControl? = null private var letterboxColor: Int = 0 + /** Background color to be used during the animation, also see [getBackgroundColor] */ + protected var customizedBackgroundColor = 0 + + /** + * Whether the entering target should be shifted vertically with the user gesture in pre-commit + */ + abstract val allowEnteringYShift: Boolean + + /** + * Subclasses must set the [startEnteringRect] and [targetEnteringRect] to define the movement + * of the enteringTarget during pre-commit phase. + */ + abstract fun preparePreCommitEnteringRectMovement() + + /** + * Returns a base transformation to apply to the entering target during pre-commit. The system + * will apply the default animation on top of it. + */ + protected open fun getPreCommitEnteringBaseTransformation(progress: Float): Transformation? = + null + override fun onConfigurationChanged(newConfiguration: Configuration) { cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) } override fun getRunner() = backAnimationRunner - private fun startBackAnimation(backMotionEvent: BackMotionEvent) { + private fun getBackgroundColor(): Int = + when { + customizedBackgroundColor != 0 -> customizedBackgroundColor + isLetterboxed -> letterboxColor + enteringTarget != null -> enteringTarget!!.taskInfo.taskDescription!!.backgroundColor + else -> 0 + } + + protected open fun startBackAnimation(backMotionEvent: BackMotionEvent) { if (enteringTarget == null || closingTarget == null) { ProtoLog.d( ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, @@ -122,8 +146,8 @@ class CrossActivityBackAnimation @Inject constructor( transaction.setAnimationTransaction() isLetterboxed = closingTarget!!.taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed - enteringHasSameLetterbox = isLetterboxed && - closingTarget!!.localBounds.equals(enteringTarget!!.localBounds) + enteringHasSameLetterbox = + isLetterboxed && closingTarget!!.localBounds.equals(enteringTarget!!.localBounds) if (isLetterboxed && !enteringHasSameLetterbox) { // Play animation with letterboxes, if closing and entering target have mismatching @@ -143,32 +167,27 @@ class CrossActivityBackAnimation @Inject constructor( targetClosingRect.scaleCentered(MAX_SCALE) if (backMotionEvent.swipeEdge != BackEvent.EDGE_RIGHT) { targetClosingRect.offset( - startClosingRect.right - targetClosingRect.right - displayBoundsMargin, 0f + startClosingRect.right - targetClosingRect.right - displayBoundsMargin, + 0f ) } - // the entering target starts 96dp to the left of the screen edge... - startEnteringRect.set(startClosingRect) - startEnteringRect.offset(-enteringStartOffset, 0f) - - // ...and gets scaled in sync with the closing target - targetEnteringRect.set(startEnteringRect) - targetEnteringRect.scaleCentered(MAX_SCALE) + preparePreCommitEnteringRectMovement() - // Draw background with task background color (or letterbox color). - val backgroundColor = if (isLetterboxed) { - letterboxColor - } else { - enteringTarget!!.taskInfo.taskDescription!!.backgroundColor - } background.ensureBackground( - closingTarget!!.windowConfiguration.bounds, backgroundColor, transaction + closingTarget!!.windowConfiguration.bounds, + getBackgroundColor(), + transaction ) ensureScrimLayer() if (isLetterboxed && enteringHasSameLetterbox) { // crop left and right letterboxes - cropRect.set(closingTarget!!.localBounds.left, 0, closingTarget!!.localBounds.right, - closingTarget!!.windowConfiguration.bounds.height()) + cropRect.set( + closingTarget!!.localBounds.left, + 0, + closingTarget!!.localBounds.right, + closingTarget!!.windowConfiguration.bounds.height() + ) // and add fake letterbox square surfaces instead ensureLetterboxes() } else { @@ -185,8 +204,14 @@ class CrossActivityBackAnimation @Inject constructor( currentClosingRect.offset(0f, yOffset) applyTransform(closingTarget?.leash, currentClosingRect, 1f) currentEnteringRect.setInterpolatedRectF(startEnteringRect, targetEnteringRect, progress) - currentEnteringRect.offset(0f, yOffset) - applyTransform(enteringTarget?.leash, currentEnteringRect, 1f) + if (allowEnteringYShift) currentEnteringRect.offset(0f, yOffset) + val enteringTransformation = getPreCommitEnteringBaseTransformation(progress) + applyTransform( + enteringTarget?.leash, + currentEnteringRect, + enteringTransformation?.alpha ?: 1f, + enteringTransformation + ) applyTransaction() } @@ -199,30 +224,25 @@ class CrossActivityBackAnimation @Inject constructor( val deltaYRatio = min(screenHeight / 2f, abs(rawYDelta)) / (screenHeight / 2f) val interpolatedYRatio: Float = verticalMoveInterpolator.getInterpolation(deltaYRatio) // limit y-shift so surface never passes 8dp screen margin - val deltaY = yDirection * interpolatedYRatio * max( - 0f, (screenHeight - centeredRect.height()) / 2f - displayBoundsMargin - ) + val deltaY = + max(0f, (screenHeight - centeredRect.height()) / 2f - displayBoundsMargin) * + interpolatedYRatio * + yDirection return deltaY } - private fun onGestureCommitted() { - if (closingTarget?.leash == null || enteringTarget?.leash == null || - !enteringTarget!!.leash.isValid || !closingTarget!!.leash.isValid + protected open fun onGestureCommitted() { + if ( + closingTarget?.leash == null || + enteringTarget?.leash == null || + !enteringTarget!!.leash.isValid || + !closingTarget!!.leash.isValid ) { finishAnimation() return } - // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current - // coordinate of the gesture driven phase. Let's update the start and target rects and kick - // off the animator - startClosingRect.set(currentClosingRect) - startEnteringRect.set(currentEnteringRect) - targetEnteringRect.set(backAnimRect) - targetClosingRect.set(backAnimRect) - targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f) - - val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_ANIMATION_DURATION) + val valueAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(POST_COMMIT_DURATION) valueAnimator.addUpdateListener { animation: ValueAnimator -> val progress = animation.animatedFraction onPostCommitProgress(progress) @@ -230,27 +250,22 @@ class CrossActivityBackAnimation @Inject constructor( background.resetStatusBarCustomization() } } - valueAnimator.addListener(object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animation: Animator) { - background.resetStatusBarCustomization() - finishAnimation() + valueAnimator.addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animation: Animator) { + background.resetStatusBarCustomization() + finishAnimation() + } } - }) + ) valueAnimator.start() } - private fun onPostCommitProgress(linearProgress: Float) { - val closingAlpha = max(1f - linearProgress * 2, 0f) - val progress = postCommitInterpolator.getInterpolation(linearProgress) + protected open fun onPostCommitProgress(linearProgress: Float) { scrimLayer?.let { transaction.setAlpha(it, maxScrimAlpha * (1f - linearProgress)) } - currentClosingRect.setInterpolatedRectF(startClosingRect, targetClosingRect, progress) - applyTransform(closingTarget?.leash, currentClosingRect, closingAlpha) - currentEnteringRect.setInterpolatedRectF(startEnteringRect, targetEnteringRect, progress) - applyTransform(enteringTarget?.leash, currentEnteringRect, 1f) - applyTransaction() } - private fun finishAnimation() { + protected open fun finishAnimation() { enteringTarget?.let { if (it.leash != null && it.leash.isValid) { transaction.setCornerRadius(it.leash, 0f) @@ -278,47 +293,56 @@ class CrossActivityBackAnimation @Inject constructor( enteringHasSameLetterbox = false } - private fun applyTransform(leash: SurfaceControl?, rect: RectF, alpha: Float) { + protected fun applyTransform( + leash: SurfaceControl?, + rect: RectF, + alpha: Float, + baseTransformation: Transformation? = null + ) { if (leash == null || !leash.isValid) return val scale = rect.width() / backAnimRect.width() - transformMatrix.reset() - val scalePivotX = if (isLetterboxed && enteringHasSameLetterbox) { - closingTarget!!.localBounds.left.toFloat() - } else { - 0f - } - transformMatrix.setScale(scale, scale, scalePivotX, 0f) - transformMatrix.postTranslate(rect.left, rect.top) - transaction.setAlpha(leash, alpha) - .setMatrix(leash, transformMatrix, tmpFloat9) + val matrix = baseTransformation?.matrix ?: transformMatrix.apply { reset() } + val scalePivotX = + if (isLetterboxed && enteringHasSameLetterbox) { + closingTarget!!.localBounds.left.toFloat() + } else { + 0f + } + matrix.postScale(scale, scale, scalePivotX, 0f) + matrix.postTranslate(rect.left, rect.top) + transaction + .setAlpha(leash, keepMinimumAlpha(alpha)) + .setMatrix(leash, matrix, tmpFloat9) .setCrop(leash, cropRect) .setCornerRadius(leash, cornerRadius) } - private fun applyTransaction() { - transaction.setFrameTimelineVsync(Choreographer.getInstance().vsyncId) + protected fun applyTransaction() { + transaction.setFrameTimelineVsync(choreographer.vsyncId) transaction.apply() } private fun ensureScrimLayer() { if (scrimLayer != null) return val isDarkTheme: Boolean = isDarkMode(context) - val scrimBuilder = SurfaceControl.Builder() - .setName("Cross-Activity back animation scrim") - .setCallsite("CrossActivityBackAnimation") - .setColorLayer() - .setOpaque(false) - .setHidden(false) + val scrimBuilder = + SurfaceControl.Builder() + .setName("Cross-Activity back animation scrim") + .setCallsite("CrossActivityBackAnimation") + .setColorLayer() + .setOpaque(false) + .setHidden(false) rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, scrimBuilder) scrimLayer = scrimBuilder.build() val colorComponents = floatArrayOf(0f, 0f, 0f) maxScrimAlpha = if (isDarkTheme) MAX_SCRIM_ALPHA_DARK else MAX_SCRIM_ALPHA_LIGHT - val scrimCrop = if (isLetterboxed) { - closingTarget!!.windowConfiguration.bounds - } else { - closingTarget!!.localBounds - } + val scrimCrop = + if (isLetterboxed) { + closingTarget!!.windowConfiguration.bounds + } else { + closingTarget!!.localBounds + } transaction .setColor(scrimLayer, colorComponents) .setAlpha(scrimLayer!!, maxScrimAlpha) @@ -339,21 +363,34 @@ class CrossActivityBackAnimation @Inject constructor( private fun ensureLetterboxes() { closingTarget?.let { t -> if (t.localBounds.left != 0 && leftLetterboxLayer == null) { - val bounds = Rect(0, t.windowConfiguration.bounds.top, t.localBounds.left, - t.windowConfiguration.bounds.bottom) + val bounds = + Rect( + 0, + t.windowConfiguration.bounds.top, + t.localBounds.left, + t.windowConfiguration.bounds.bottom + ) leftLetterboxLayer = ensureLetterbox(bounds) } - if (t.localBounds.right != t.windowConfiguration.bounds.right && - rightLetterboxLayer == null) { - val bounds = Rect(t.localBounds.right, t.windowConfiguration.bounds.top, - t.windowConfiguration.bounds.right, t.windowConfiguration.bounds.bottom) + if ( + t.localBounds.right != t.windowConfiguration.bounds.right && + rightLetterboxLayer == null + ) { + val bounds = + Rect( + t.localBounds.right, + t.windowConfiguration.bounds.top, + t.windowConfiguration.bounds.right, + t.windowConfiguration.bounds.bottom + ) rightLetterboxLayer = ensureLetterbox(bounds) } } } private fun ensureLetterbox(bounds: Rect): SurfaceControl { - val letterboxBuilder = SurfaceControl.Builder() + val letterboxBuilder = + SurfaceControl.Builder() .setName("Cross-Activity back animation letterbox") .setCallsite("CrossActivityBackAnimation") .setColorLayer() @@ -362,13 +399,17 @@ class CrossActivityBackAnimation @Inject constructor( rootTaskDisplayAreaOrganizer.attachToDisplayArea(Display.DEFAULT_DISPLAY, letterboxBuilder) val layer = letterboxBuilder.build() - val colorComponents = floatArrayOf(Color.red(letterboxColor) / 255f, - Color.green(letterboxColor) / 255f, Color.blue(letterboxColor) / 255f) + val colorComponents = + floatArrayOf( + Color.red(letterboxColor) / 255f, + Color.green(letterboxColor) / 255f, + Color.blue(letterboxColor) / 255f + ) transaction - .setColor(layer, colorComponents) - .setCrop(layer, bounds) - .setRelativeLayer(layer, closingTarget!!.leash, 1) - .show(layer) + .setColor(layer, colorComponents) + .setCrop(layer, bounds) + .setRelativeLayer(layer, closingTarget!!.leash, 1) + .show(layer) return layer } @@ -389,8 +430,8 @@ class CrossActivityBackAnimation @Inject constructor( } override fun prepareNextAnimation( - animationInfo: BackNavigationInfo.CustomAnimationInfo?, - letterboxColor: Int + animationInfo: BackNavigationInfo.CustomAnimationInfo?, + letterboxColor: Int ): Boolean { this.letterboxColor = letterboxColor return false @@ -415,9 +456,7 @@ class CrossActivityBackAnimation @Inject constructor( } override fun onBackCancelled() { - progressAnimator.onBackCancelled { - finishAnimation() - } + progressAnimator.onBackCancelled { finishAnimation() } } override fun onBackInvoked() { @@ -435,7 +474,8 @@ class CrossActivityBackAnimation @Inject constructor( finishedCallback: IRemoteAnimationFinishedCallback ) { ProtoLog.d( - ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, "Start back to activity animation." + ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, + "Start back to activity animation." ) for (a in apps) { when (a.mode) { @@ -452,23 +492,25 @@ class CrossActivityBackAnimation @Inject constructor( } companion object { - /** Max scale of the entering/closing window.*/ - private const val MAX_SCALE = 0.9f - - /** Duration of post animation after gesture committed. */ - private const val POST_ANIMATION_DURATION = 300L - + /** Max scale of the closing window. */ + internal const val MAX_SCALE = 0.9f private const val MAX_SCRIM_ALPHA_DARK = 0.8f private const val MAX_SCRIM_ALPHA_LIGHT = 0.2f + private const val POST_COMMIT_DURATION = 300L } } +// The target will loose focus when alpha == 0, so keep a minimum value for it. +private fun keepMinimumAlpha(transAlpha: Float): Float { + return max(transAlpha.toDouble(), 0.005).toFloat() +} + private fun isDarkMode(context: Context): Boolean { return context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == - Configuration.UI_MODE_NIGHT_YES + Configuration.UI_MODE_NIGHT_YES } -private fun RectF.setInterpolatedRectF(start: RectF, target: RectF, progress: Float) { +internal fun RectF.setInterpolatedRectF(start: RectF, target: RectF, progress: Float) { require(!(progress < 0 || progress > 1)) { "Progress value must be between 0 and 1" } left = start.left + (target.left - start.left) * progress top = start.top + (target.top - start.top) * progress @@ -476,7 +518,7 @@ private fun RectF.setInterpolatedRectF(start: RectF, target: RectF, progress: Fl bottom = start.bottom + (target.bottom - start.bottom) * progress } -private fun RectF.scaleCentered( +internal fun RectF.scaleCentered( scale: Float, pivotX: Float = left + width() / 2, pivotY: Float = top + height() / 2 diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt new file mode 100644 index 000000000000..e6ec2b449616 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomCrossActivityBackAnimation.kt @@ -0,0 +1,256 @@ +/* + * 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.back + +import android.content.Context +import android.graphics.Rect +import android.graphics.RectF +import android.util.MathUtils +import android.view.Choreographer +import android.view.SurfaceControl +import android.view.animation.Animation +import android.view.animation.Transformation +import android.window.BackMotionEvent +import android.window.BackNavigationInfo +import com.android.internal.R +import com.android.internal.policy.TransitionAnimation +import com.android.internal.protolog.common.ProtoLog +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.protolog.ShellProtoLogGroup +import com.android.wm.shell.shared.annotations.ShellMainThread +import javax.inject.Inject + +/** Class that handles customized predictive cross activity back animations. */ +@ShellMainThread +class CustomCrossActivityBackAnimation( + context: Context, + background: BackAnimationBackground, + rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer, + transaction: SurfaceControl.Transaction, + choreographer: Choreographer, + private val customAnimationLoader: CustomAnimationLoader +) : + CrossActivityBackAnimation( + context, + background, + rootTaskDisplayAreaOrganizer, + transaction, + choreographer + ) { + + private var enterAnimation: Animation? = null + private var closeAnimation: Animation? = null + private val transformation = Transformation() + private var gestureProgress = 0f + + override val allowEnteringYShift = false + + @Inject + constructor( + context: Context, + background: BackAnimationBackground, + rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer + ) : this( + context, + background, + rootTaskDisplayAreaOrganizer, + SurfaceControl.Transaction(), + Choreographer.getInstance(), + CustomAnimationLoader( + TransitionAnimation(context, false /* debug */, "CustomCrossActivityBackAnimation") + ) + ) + + override fun preparePreCommitEnteringRectMovement() { + // No movement for the entering rect + startEnteringRect.set(startClosingRect) + targetEnteringRect.set(startClosingRect) + } + + override fun getPreCommitEnteringBaseTransformation(progress: Float): Transformation { + gestureProgress = progress + transformation.clear() + enterAnimation!!.getTransformationAt(progress * PRE_COMMIT_MAX_PROGRESS, transformation) + return transformation + } + + override fun startBackAnimation(backMotionEvent: BackMotionEvent) { + super.startBackAnimation(backMotionEvent) + if ( + closeAnimation == null || + enterAnimation == null || + closingTarget == null || + enteringTarget == null + ) { + ProtoLog.d( + ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, + "Enter animation or close animation is null." + ) + return + } + initializeAnimation(closeAnimation!!, closingTarget!!.localBounds) + initializeAnimation(enterAnimation!!, enteringTarget!!.localBounds) + } + + override fun onPostCommitProgress(linearProgress: Float) { + super.onPostCommitProgress(linearProgress) + if (closingTarget == null || enteringTarget == null) return + + // TODO: Should we use the duration from the custom xml spec for the post-commit animation? + applyTransform(closingTarget!!.leash, currentClosingRect, linearProgress, closeAnimation!!) + val enteringProgress = + MathUtils.lerp(gestureProgress * PRE_COMMIT_MAX_PROGRESS, 1f, linearProgress) + applyTransform( + enteringTarget!!.leash, + currentEnteringRect, + enteringProgress, + enterAnimation!! + ) + applyTransaction() + } + + private fun applyTransform( + leash: SurfaceControl, + rect: RectF, + progress: Float, + animation: Animation + ) { + transformation.clear() + animation.getTransformationAt(progress, transformation) + applyTransform(leash, rect, transformation.alpha, transformation) + } + + override fun finishAnimation() { + closeAnimation?.reset() + closeAnimation = null + enterAnimation?.reset() + enterAnimation = null + transformation.clear() + gestureProgress = 0f + super.finishAnimation() + } + + /** Load customize animation before animation start. */ + override fun prepareNextAnimation( + animationInfo: BackNavigationInfo.CustomAnimationInfo?, + letterboxColor: Int + ): Boolean { + super.prepareNextAnimation(animationInfo, letterboxColor) + if (animationInfo == null) return false + customAnimationLoader.loadAll(animationInfo)?.let { result -> + closeAnimation = result.closeAnimation + enterAnimation = result.enterAnimation + customizedBackgroundColor = result.backgroundColor + return true + } + return false + } + + class AnimationLoadResult { + var closeAnimation: Animation? = null + var enterAnimation: Animation? = null + var backgroundColor = 0 + } + + companion object { + private const val PRE_COMMIT_MAX_PROGRESS = 0.2f + } +} + +/** Helper class to load custom animation. */ +class CustomAnimationLoader(private val transitionAnimation: TransitionAnimation) { + + /** + * Load both enter and exit animation for the close activity transition. Note that the result is + * only valid if the exit animation has set and loaded success. If the entering animation has + * not set(i.e. 0), here will load the default entering animation for it. + * + * @param animationInfo The information of customize animation, which can be set from + * [Activity.overrideActivityTransition] and/or [LayoutParams.windowAnimations] + */ + fun loadAll( + animationInfo: BackNavigationInfo.CustomAnimationInfo + ): CustomCrossActivityBackAnimation.AnimationLoadResult? { + if (animationInfo.packageName.isEmpty()) return null + val close = loadAnimation(animationInfo, false) ?: return null + val open = loadAnimation(animationInfo, true) + val result = CustomCrossActivityBackAnimation.AnimationLoadResult() + result.closeAnimation = close + result.enterAnimation = open + result.backgroundColor = animationInfo.customBackground + return result + } + + /** + * Load enter or exit animation from CustomAnimationInfo + * + * @param animationInfo The information for customize animation. + * @param enterAnimation true when load for enter animation, false for exit animation. + * @return Loaded animation. + */ + fun loadAnimation( + animationInfo: BackNavigationInfo.CustomAnimationInfo, + enterAnimation: Boolean + ): Animation? { + var a: Animation? = null + // Activity#overrideActivityTransition has higher priority than windowAnimations + // Try to get animation from Activity#overrideActivityTransition + if ( + enterAnimation && animationInfo.customEnterAnim != 0 || + !enterAnimation && animationInfo.customExitAnim != 0 + ) { + a = + transitionAnimation.loadAppTransitionAnimation( + animationInfo.packageName, + if (enterAnimation) animationInfo.customEnterAnim + else animationInfo.customExitAnim + ) + } else if (animationInfo.windowAnimations != 0) { + // try to get animation from LayoutParams#windowAnimations + a = + transitionAnimation.loadAnimationAttr( + animationInfo.packageName, + animationInfo.windowAnimations, + if (enterAnimation) R.styleable.WindowAnimation_activityCloseEnterAnimation + else R.styleable.WindowAnimation_activityCloseExitAnimation, + false /* translucent */ + ) + } + // Only allow to load default animation for opening target. + if (a == null && enterAnimation) { + a = loadDefaultOpenAnimation() + } + if (a != null) { + ProtoLog.d(ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, "custom animation loaded %s", a) + } else { + ProtoLog.e(ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW, "No custom animation loaded") + } + return a + } + + private fun loadDefaultOpenAnimation(): Animation? { + return transitionAnimation.loadDefaultAnimationAttr( + R.styleable.WindowAnimation_activityCloseEnterAnimation, + false /* translucent */ + ) + } +} + +private fun initializeAnimation(animation: Animation, bounds: Rect) { + val width = bounds.width() + val height = bounds.height() + animation.initialize(width, height, width, height) +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java deleted file mode 100644 index e27b40e58591..000000000000 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CustomizeActivityAnimation.java +++ /dev/null @@ -1,443 +0,0 @@ -/* - * 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.wm.shell.back; - -import static android.view.RemoteAnimationTarget.MODE_CLOSING; -import static android.view.RemoteAnimationTarget.MODE_OPENING; - -import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY; -import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW; - -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.app.Activity; -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Color; -import android.graphics.Rect; -import android.os.RemoteException; -import android.util.FloatProperty; -import android.view.Choreographer; -import android.view.IRemoteAnimationFinishedCallback; -import android.view.IRemoteAnimationRunner; -import android.view.RemoteAnimationTarget; -import android.view.SurfaceControl; -import android.view.WindowManager.LayoutParams; -import android.view.animation.Animation; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Transformation; -import android.window.BackEvent; -import android.window.BackMotionEvent; -import android.window.BackNavigationInfo; -import android.window.BackProgressAnimator; -import android.window.IOnBackInvokedCallback; - -import com.android.internal.R; -import com.android.internal.dynamicanimation.animation.SpringAnimation; -import com.android.internal.dynamicanimation.animation.SpringForce; -import com.android.internal.policy.ScreenDecorationsUtils; -import com.android.internal.policy.TransitionAnimation; -import com.android.internal.protolog.common.ProtoLog; -import com.android.wm.shell.shared.annotations.ShellMainThread; - -import javax.inject.Inject; - -/** Class that handle customized close activity transition animation. */ -@ShellMainThread -public class CustomizeActivityAnimation extends ShellBackAnimation { - private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator(); - private final BackAnimationRunner mBackAnimationRunner; - private float mCornerRadius; - private final SurfaceControl.Transaction mTransaction; - private final BackAnimationBackground mBackground; - private RemoteAnimationTarget mEnteringTarget; - private RemoteAnimationTarget mClosingTarget; - private IRemoteAnimationFinishedCallback mFinishCallback; - /** Duration of post animation after gesture committed. */ - private static final int POST_ANIMATION_DURATION = 250; - - private static final int SCALE_FACTOR = 1000; - private final SpringAnimation mProgressSpring; - private float mLatestProgress = 0.0f; - - private static final float TARGET_COMMIT_PROGRESS = 0.5f; - - private final float[] mTmpFloat9 = new float[9]; - private final DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator(); - - final CustomAnimationLoader mCustomAnimationLoader; - private Animation mEnterAnimation; - private Animation mCloseAnimation; - private int mNextBackgroundColor; - final Transformation mTransformation = new Transformation(); - - private final Choreographer mChoreographer; - private final Context mContext; - - @Inject - public CustomizeActivityAnimation(Context context, BackAnimationBackground background) { - this(context, background, new SurfaceControl.Transaction(), null); - } - - CustomizeActivityAnimation(Context context, BackAnimationBackground background, - SurfaceControl.Transaction transaction, Choreographer choreographer) { - mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context); - mBackground = background; - mBackAnimationRunner = new BackAnimationRunner( - new Callback(), new Runner(), context, CUJ_PREDICTIVE_BACK_CROSS_ACTIVITY); - mCustomAnimationLoader = new CustomAnimationLoader(context); - - mProgressSpring = new SpringAnimation(this, ENTER_PROGRESS_PROP); - mProgressSpring.setSpring(new SpringForce() - .setStiffness(SpringForce.STIFFNESS_MEDIUM) - .setDampingRatio(SpringForce.DAMPING_RATIO_NO_BOUNCY)); - mTransaction = transaction == null ? new SurfaceControl.Transaction() : transaction; - mChoreographer = choreographer != null ? choreographer : Choreographer.getInstance(); - mContext = context; - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext); - } - - private float getLatestProgress() { - return mLatestProgress * SCALE_FACTOR; - } - private void setLatestProgress(float value) { - mLatestProgress = value / SCALE_FACTOR; - applyTransformTransaction(mLatestProgress); - } - - private static final FloatProperty<CustomizeActivityAnimation> ENTER_PROGRESS_PROP = - new FloatProperty<>("enter") { - @Override - public void setValue(CustomizeActivityAnimation anim, float value) { - anim.setLatestProgress(value); - } - - @Override - public Float get(CustomizeActivityAnimation object) { - return object.getLatestProgress(); - } - }; - - // The target will lose focus when alpha == 0, so keep a minimum value for it. - private static float keepMinimumAlpha(float transAlpha) { - return Math.max(transAlpha, 0.005f); - } - - private static void initializeAnimation(Animation animation, Rect bounds) { - final int width = bounds.width(); - final int height = bounds.height(); - animation.initialize(width, height, width, height); - } - - private void startBackAnimation() { - if (mEnteringTarget == null || mClosingTarget == null - || mCloseAnimation == null || mEnterAnimation == null) { - ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Entering target or closing target is null."); - return; - } - initializeAnimation(mCloseAnimation, mClosingTarget.localBounds); - initializeAnimation(mEnterAnimation, mEnteringTarget.localBounds); - - // Draw background with task background color. - if (mEnteringTarget.taskInfo != null && mEnteringTarget.taskInfo.taskDescription != null) { - mBackground.ensureBackground(mClosingTarget.windowConfiguration.getBounds(), - mNextBackgroundColor == Color.TRANSPARENT - ? mEnteringTarget.taskInfo.taskDescription.getBackgroundColor() - : mNextBackgroundColor, - mTransaction); - } - } - - private void applyTransformTransaction(float progress) { - if (mClosingTarget == null || mEnteringTarget == null) { - return; - } - applyTransform(mClosingTarget.leash, progress, mCloseAnimation); - applyTransform(mEnteringTarget.leash, progress, mEnterAnimation); - mTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId()); - mTransaction.apply(); - } - - private void applyTransform(SurfaceControl leash, float progress, Animation animation) { - mTransformation.clear(); - animation.getTransformationAt(progress, mTransformation); - mTransaction.setMatrix(leash, mTransformation.getMatrix(), mTmpFloat9); - mTransaction.setAlpha(leash, keepMinimumAlpha(mTransformation.getAlpha())); - mTransaction.setCornerRadius(leash, mCornerRadius); - } - - void finishAnimation() { - if (mCloseAnimation != null) { - mCloseAnimation.reset(); - mCloseAnimation = null; - } - if (mEnterAnimation != null) { - mEnterAnimation.reset(); - mEnterAnimation = null; - } - if (mEnteringTarget != null) { - mEnteringTarget.leash.release(); - mEnteringTarget = null; - } - if (mClosingTarget != null) { - mClosingTarget.leash.release(); - mClosingTarget = null; - } - if (mBackground != null) { - mBackground.removeBackground(mTransaction); - } - mTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId()); - mTransaction.apply(); - mTransformation.clear(); - mLatestProgress = 0; - mNextBackgroundColor = Color.TRANSPARENT; - if (mFinishCallback != null) { - try { - mFinishCallback.onAnimationFinished(); - } catch (RemoteException e) { - e.printStackTrace(); - } - mFinishCallback = null; - } - mProgressSpring.animateToFinalPosition(0); - mProgressSpring.skipToEnd(); - } - - void onGestureProgress(@NonNull BackEvent backEvent) { - if (mEnteringTarget == null || mClosingTarget == null - || mCloseAnimation == null || mEnterAnimation == null) { - return; - } - - final float progress = backEvent.getProgress(); - - float springProgress = (progress > 0.1f - ? mapLinear(progress, 0.1f, 1f, TARGET_COMMIT_PROGRESS, 1f) - : mapLinear(progress, 0, 1f, 0f, TARGET_COMMIT_PROGRESS)) * SCALE_FACTOR; - - mProgressSpring.animateToFinalPosition(springProgress); - } - - static float mapLinear(float x, float a1, float a2, float b1, float b2) { - return b1 + (x - a1) * (b2 - b1) / (a2 - a1); - } - - void onGestureCommitted() { - if (mEnteringTarget == null || mClosingTarget == null - || mCloseAnimation == null || mEnterAnimation == null) { - finishAnimation(); - return; - } - mProgressSpring.cancel(); - - // Enter phase 2 of the animation - final ValueAnimator valueAnimator = ValueAnimator.ofFloat(mLatestProgress, 1f) - .setDuration(POST_ANIMATION_DURATION); - valueAnimator.setInterpolator(mDecelerateInterpolator); - valueAnimator.addUpdateListener(animation -> { - float progress = (float) animation.getAnimatedValue(); - applyTransformTransaction(progress); - }); - - valueAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - finishAnimation(); - } - }); - valueAnimator.start(); - } - - /** Load customize animation before animation start. */ - @Override - public boolean prepareNextAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo, - int letterboxColor) { - if (animationInfo == null) { - return false; - } - final AnimationLoadResult result = mCustomAnimationLoader.loadAll(animationInfo); - if (result != null) { - mCloseAnimation = result.mCloseAnimation; - mEnterAnimation = result.mEnterAnimation; - mNextBackgroundColor = result.mBackgroundColor; - return true; - } - return false; - } - - @Override - public BackAnimationRunner getRunner() { - return mBackAnimationRunner; - } - - private final class Callback extends IOnBackInvokedCallback.Default { - @Override - public void onBackStarted(BackMotionEvent backEvent) { - // in case we're still animating an onBackCancelled event, let's remove the finish- - // callback from the progress animator to prevent calling finishAnimation() before - // restarting a new animation - mProgressAnimator.removeOnBackCancelledFinishCallback(); - - mProgressAnimator.onBackStarted(backEvent, - CustomizeActivityAnimation.this::onGestureProgress); - } - - @Override - public void onBackProgressed(@NonNull BackMotionEvent backEvent) { - mProgressAnimator.onBackProgressed(backEvent); - } - - @Override - public void onBackCancelled() { - mProgressAnimator.onBackCancelled(CustomizeActivityAnimation.this::finishAnimation); - } - - @Override - public void onBackInvoked() { - mProgressAnimator.reset(); - onGestureCommitted(); - } - } - - private final class Runner extends IRemoteAnimationRunner.Default { - @Override - public void onAnimationStart( - int transit, - RemoteAnimationTarget[] apps, - RemoteAnimationTarget[] wallpapers, - RemoteAnimationTarget[] nonApps, - IRemoteAnimationFinishedCallback finishedCallback) { - ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Start back to customize animation."); - for (RemoteAnimationTarget a : apps) { - if (a.mode == MODE_CLOSING) { - mClosingTarget = a; - } - if (a.mode == MODE_OPENING) { - mEnteringTarget = a; - } - } - if (mCloseAnimation == null || mEnterAnimation == null) { - ProtoLog.d(WM_SHELL_BACK_PREVIEW, - "No animation loaded, should choose cross-activity animation?"); - } - - startBackAnimation(); - mFinishCallback = finishedCallback; - } - - @Override - public void onAnimationCancelled() { - finishAnimation(); - } - } - - - static final class AnimationLoadResult { - Animation mCloseAnimation; - Animation mEnterAnimation; - int mBackgroundColor; - } - - /** - * Helper class to load custom animation. - */ - static class CustomAnimationLoader { - final TransitionAnimation mTransitionAnimation; - - CustomAnimationLoader(Context context) { - mTransitionAnimation = new TransitionAnimation( - context, false /* debug */, "CustomizeBackAnimation"); - } - - /** - * Load both enter and exit animation for the close activity transition. - * Note that the result is only valid if the exit animation has set and loaded success. - * If the entering animation has not set(i.e. 0), here will load the default entering - * animation for it. - * - * @param animationInfo The information of customize animation, which can be set from - * {@link Activity#overrideActivityTransition} and/or - * {@link LayoutParams#windowAnimations} - */ - AnimationLoadResult loadAll(BackNavigationInfo.CustomAnimationInfo animationInfo) { - if (animationInfo.getPackageName().isEmpty()) { - return null; - } - final Animation close = loadAnimation(animationInfo, false); - if (close == null) { - return null; - } - final Animation open = loadAnimation(animationInfo, true); - AnimationLoadResult result = new AnimationLoadResult(); - result.mCloseAnimation = close; - result.mEnterAnimation = open; - result.mBackgroundColor = animationInfo.getCustomBackground(); - return result; - } - - /** - * Load enter or exit animation from CustomAnimationInfo - * @param animationInfo The information for customize animation. - * @param enterAnimation true when load for enter animation, false for exit animation. - * @return Loaded animation. - */ - @Nullable - Animation loadAnimation(BackNavigationInfo.CustomAnimationInfo animationInfo, - boolean enterAnimation) { - Animation a = null; - // Activity#overrideActivityTransition has higher priority than windowAnimations - // Try to get animation from Activity#overrideActivityTransition - if ((enterAnimation && animationInfo.getCustomEnterAnim() != 0) - || (!enterAnimation && animationInfo.getCustomExitAnim() != 0)) { - a = mTransitionAnimation.loadAppTransitionAnimation( - animationInfo.getPackageName(), - enterAnimation ? animationInfo.getCustomEnterAnim() - : animationInfo.getCustomExitAnim()); - } else if (animationInfo.getWindowAnimations() != 0) { - // try to get animation from LayoutParams#windowAnimations - a = mTransitionAnimation.loadAnimationAttr(animationInfo.getPackageName(), - animationInfo.getWindowAnimations(), enterAnimation - ? R.styleable.WindowAnimation_activityCloseEnterAnimation - : R.styleable.WindowAnimation_activityCloseExitAnimation, - false /* translucent */); - } - // Only allow to load default animation for opening target. - if (a == null && enterAnimation) { - a = loadDefaultOpenAnimation(); - } - if (a != null) { - ProtoLog.d(WM_SHELL_BACK_PREVIEW, "custom animation loaded %s", a); - } else { - ProtoLog.e(WM_SHELL_BACK_PREVIEW, "No custom animation loaded"); - } - return a; - } - - private Animation loadDefaultOpenAnimation() { - return mTransitionAnimation.loadDefaultAnimationAttr( - R.styleable.WindowAnimation_activityCloseEnterAnimation, - false /* translucent */); - } - } -} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt new file mode 100644 index 000000000000..f33c5b9bd183 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/DefaultCrossActivityBackAnimation.kt @@ -0,0 +1,81 @@ +/* + * 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.back + +import android.content.Context +import android.view.Choreographer +import android.view.SurfaceControl +import com.android.wm.shell.R +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.animation.Interpolators +import com.android.wm.shell.shared.annotations.ShellMainThread +import javax.inject.Inject +import kotlin.math.max + +/** Class that defines cross-activity animation. */ +@ShellMainThread +class DefaultCrossActivityBackAnimation +@Inject +constructor( + context: Context, + background: BackAnimationBackground, + rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer +) : + CrossActivityBackAnimation( + context, + background, + rootTaskDisplayAreaOrganizer, + SurfaceControl.Transaction(), + Choreographer.getInstance() + ) { + + private val postCommitInterpolator = Interpolators.FAST_OUT_SLOW_IN + private val enteringStartOffset = + context.resources.getDimension(R.dimen.cross_activity_back_entering_start_offset) + override val allowEnteringYShift = true + + override fun preparePreCommitEnteringRectMovement() { + // the entering target starts 96dp to the left of the screen edge... + startEnteringRect.set(startClosingRect) + startEnteringRect.offset(-enteringStartOffset, 0f) + // ...and gets scaled in sync with the closing target + targetEnteringRect.set(startEnteringRect) + targetEnteringRect.scaleCentered(MAX_SCALE) + } + + override fun onGestureCommitted() { + // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current + // coordinate of the gesture driven phase. Let's update the start and target rects and kick + // off the animator in the superclass + startClosingRect.set(currentClosingRect) + startEnteringRect.set(currentEnteringRect) + targetEnteringRect.set(backAnimRect) + targetClosingRect.set(backAnimRect) + targetClosingRect.offset(currentClosingRect.left + enteringStartOffset, 0f) + super.onGestureCommitted() + } + + override fun onPostCommitProgress(linearProgress: Float) { + super.onPostCommitProgress(linearProgress) + val closingAlpha = max(1f - linearProgress * 2, 0f) + val progress = postCommitInterpolator.getInterpolation(linearProgress) + currentClosingRect.setInterpolatedRectF(startClosingRect, targetClosingRect, progress) + applyTransform(closingTarget?.leash, currentClosingRect, closingAlpha) + currentEnteringRect.setInterpolatedRectF(startEnteringRect, targetEnteringRect, progress) + applyTransform(enteringTarget?.leash, currentEnteringRect, 1f) + applyTransaction() + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index 5c292f173e5b..bfac24b81d2f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -188,6 +188,11 @@ public class CompatUIController implements OnDisplaysChangedListener, */ private boolean mHasShownUserAspectRatioSettingsButton = false; + /** + * This is true when the rechability education is displayed for the first time. + */ + private boolean mIsFirstReachabilityEducationRunning; + public CompatUIController(@NonNull Context context, @NonNull ShellInit shellInit, @NonNull ShellController shellController, @@ -252,9 +257,35 @@ public class CompatUIController implements OnDisplaysChangedListener, removeLayouts(taskInfo.taskId); return; } - + // We're showing the first reachability education so we ignore incoming TaskInfo + // until the education flow has completed or we double tap. + if (mIsFirstReachabilityEducationRunning) { + return; + } + if (taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed) { + if (taskInfo.appCompatTaskInfo.isLetterboxEducationEnabled) { + createOrUpdateLetterboxEduLayout(taskInfo, taskListener); + } else if (!taskInfo.appCompatTaskInfo.isFromLetterboxDoubleTap) { + // In this case the app is letterboxed and the letterbox education + // is disabled. In this case we need to understand if it's the first + // time we show the reachability education. When this is happening + // we need to ignore all the incoming TaskInfo until the education + // completes. If we come from a double tap we follow the normal flow. + final boolean topActivityPillarboxed = + taskInfo.appCompatTaskInfo.isTopActivityPillarboxed(); + final boolean isFirstTimeHorizontalReachabilityEdu = topActivityPillarboxed + && !mCompatUIConfiguration.hasSeenHorizontalReachabilityEducation(taskInfo); + final boolean isFirstTimeVerticalReachabilityEdu = !topActivityPillarboxed + && !mCompatUIConfiguration.hasSeenVerticalReachabilityEducation(taskInfo); + if (isFirstTimeHorizontalReachabilityEdu || isFirstTimeVerticalReachabilityEdu) { + mIsFirstReachabilityEducationRunning = true; + mCompatUIConfiguration.setSeenLetterboxEducation(taskInfo.userId); + createOrUpdateReachabilityEduLayout(taskInfo, taskListener); + return; + } + } + } createOrUpdateCompatLayout(taskInfo, taskListener); - createOrUpdateLetterboxEduLayout(taskInfo, taskListener); createOrUpdateRestartDialogLayout(taskInfo, taskListener); if (mCompatUIConfiguration.getHasSeenLetterboxEducation(taskInfo.userId)) { createOrUpdateReachabilityEduLayout(taskInfo, taskListener); @@ -589,6 +620,7 @@ public class CompatUIController implements OnDisplaysChangedListener, private void onInitialReachabilityEduDismissed(@NonNull TaskInfo taskInfo, @NonNull ShellTaskOrganizer.TaskListener taskListener) { // We need to update the UI otherwise it will not be shown until the user relaunches the app + mIsFirstReachabilityEducationRunning = false; createOrUpdateUserAspectRatioSettingsLayout(taskInfo, taskListener); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java index 795bc1a7113b..d2895b149b2c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/back/ShellBackAnimationModule.java @@ -16,9 +16,9 @@ package com.android.wm.shell.dagger.back; -import com.android.wm.shell.back.CrossActivityBackAnimation; import com.android.wm.shell.back.CrossTaskBackAnimation; -import com.android.wm.shell.back.CustomizeActivityAnimation; +import com.android.wm.shell.back.CustomCrossActivityBackAnimation; +import com.android.wm.shell.back.DefaultCrossActivityBackAnimation; import com.android.wm.shell.back.ShellBackAnimation; import com.android.wm.shell.back.ShellBackAnimationRegistry; @@ -47,7 +47,7 @@ public interface ShellBackAnimationModule { @Binds @ShellBackAnimation.CrossActivity ShellBackAnimation bindCrossActivityShellBackAnimation( - CrossActivityBackAnimation crossActivityBackAnimation); + DefaultCrossActivityBackAnimation defaultCrossActivityBackAnimation); /** Default cross task back animation */ @Binds @@ -59,5 +59,5 @@ public interface ShellBackAnimationModule { @Binds @ShellBackAnimation.CustomizeActivity ShellBackAnimation provideCustomizeActivityShellBackAnimation( - CustomizeActivityAnimation customizeActivityAnimation); + CustomCrossActivityBackAnimation customCrossActivityBackAnimation); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java index 6e61f22ca563..414a9d1151ac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java @@ -132,6 +132,7 @@ public abstract class Pip2Module { PhonePipMenuController menuPhoneController, PipBoundsAlgorithm pipBoundsAlgorithm, @NonNull PipBoundsState pipBoundsState, + @NonNull PipTransitionState pipTransitionState, @NonNull SizeSpecSource sizeSpecSource, PipMotionHelper pipMotionHelper, FloatingContentCoordinator floatingContentCoordinator, @@ -139,8 +140,9 @@ public abstract class Pip2Module { @ShellMainThread ShellExecutor mainExecutor, Optional<PipPerfHintController> pipPerfHintControllerOptional) { return new PipTouchHandler(context, shellInit, menuPhoneController, pipBoundsAlgorithm, - pipBoundsState, sizeSpecSource, pipMotionHelper, floatingContentCoordinator, - pipUiEventLogger, mainExecutor, pipPerfHintControllerOptional); + pipBoundsState, pipTransitionState, sizeSpecSource, pipMotionHelper, + floatingContentCoordinator, pipUiEventLogger, mainExecutor, + pipPerfHintControllerOptional); } @WMSingleton @@ -149,9 +151,13 @@ public abstract class Pip2Module { PipBoundsState pipBoundsState, PhonePipMenuController menuController, PipSnapAlgorithm pipSnapAlgorithm, FloatingContentCoordinator floatingContentCoordinator, - Optional<PipPerfHintController> pipPerfHintControllerOptional) { + PipScheduler pipScheduler, + Optional<PipPerfHintController> pipPerfHintControllerOptional, + PipBoundsAlgorithm pipBoundsAlgorithm, + PipTransitionState pipTransitionState) { return new PipMotionHelper(context, pipBoundsState, menuController, pipSnapAlgorithm, - floatingContentCoordinator, pipPerfHintControllerOptional); + floatingContentCoordinator, pipScheduler, pipPerfHintControllerOptional, + pipBoundsAlgorithm, pipTransitionState); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java index b41454d932a5..5af4c3b0a716 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeStatus.java @@ -41,15 +41,6 @@ public class DesktopModeStatus { public static final boolean IS_DISPLAY_CHANGE_ENABLED = SystemProperties.getBoolean( "persist.wm.debug.desktop_change_display", false); - - /** - * Flag to indicate that desktop stashing is enabled. - * When enabled, swiping home from desktop stashes the open apps. Next app that launches, - * will be added to the desktop. - */ - private static final boolean IS_STASHING_ENABLED = SystemProperties.getBoolean( - "persist.wm.debug.desktop_stashing", false); - /** * Flag to indicate whether to apply shadows to windows in desktop mode. */ @@ -109,14 +100,6 @@ public class DesktopModeStatus { } /** - * Return {@code true} if desktop task stashing is enabled when going home. - * Allows users to use home screen to add tasks to desktop. - */ - public static boolean isStashingEnabled() { - return IS_STASHING_ENABLED; - } - - /** * Return whether to use window shadows. * * @param isFocusedWindow whether the window to apply shadows to is focused diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt index 2d508b2e6e3d..6bbc8fec2894 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt @@ -48,7 +48,6 @@ class DesktopModeTaskRepository { val activeTasks: ArraySet<Int> = ArraySet(), val visibleTasks: ArraySet<Int> = ArraySet(), val minimizedTasks: ArraySet<Int> = ArraySet(), - var stashed: Boolean = false ) // Token of the current wallpaper activity, used to remove it when the last task is removed @@ -95,10 +94,8 @@ class DesktopModeTaskRepository { visibleTasksListeners[visibleTasksListener] = executor displayData.keyIterator().forEach { displayId -> val visibleTasksCount = getVisibleTaskCount(displayId) - val stashed = isStashed(displayId) executor.execute { visibleTasksListener.onTasksVisibilityChanged(displayId, visibleTasksCount) - visibleTasksListener.onStashedChanged(displayId, stashed) } } } @@ -400,26 +397,6 @@ class DesktopModeTaskRepository { } /** - * Update stashed status on display with id [displayId] - */ - fun setStashed(displayId: Int, stashed: Boolean) { - val data = displayData.getOrCreate(displayId) - val oldValue = data.stashed - data.stashed = stashed - if (oldValue != stashed) { - KtProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTaskRepo: mark stashed=%b displayId=%d", - stashed, - displayId - ) - visibleTasksListeners.forEach { (listener, executor) -> - executor.execute { listener.onStashedChanged(displayId, stashed) } - } - } - } - - /** * Removes and returns the bounds saved before maximizing the given task. */ fun removeBoundsBeforeMaximize(taskId: Int): Rect? { @@ -433,13 +410,6 @@ class DesktopModeTaskRepository { boundsBeforeMaximizeByTaskId.set(taskId, Rect(bounds)) } - /** - * Check if display with id [displayId] has desktop tasks stashed - */ - fun isStashed(displayId: Int): Boolean { - return displayData[displayId]?.stashed ?: false - } - internal fun dump(pw: PrintWriter, prefix: String) { val innerPrefix = "$prefix " pw.println("${prefix}DesktopModeTaskRepository") @@ -455,7 +425,6 @@ class DesktopModeTaskRepository { pw.println("${prefix}Display $displayId:") pw.println("${innerPrefix}activeTasks=${data.activeTasks.toDumpString()}") pw.println("${innerPrefix}visibleTasks=${data.visibleTasks.toDumpString()}") - pw.println("${innerPrefix}stashed=${data.stashed}") } } 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 b0d59231500b..b2bdbfefb9aa 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 @@ -240,34 +240,6 @@ class DesktopTasksController( } } - /** - * Stash desktop tasks on display with id [displayId]. - * - * When desktop tasks are stashed, launcher home screen icons are fully visible. New apps - * launched in this state will be added to the desktop. Existing desktop tasks will be brought - * back to front during the launch. - */ - fun stashDesktopApps(displayId: Int) { - if (DesktopModeStatus.isStashingEnabled()) { - KtProtoLog.v(WM_SHELL_DESKTOP_MODE, "DesktopTasksController: stashDesktopApps") - desktopModeTaskRepository.setStashed(displayId, true) - } - } - - /** - * Clear the stashed state for the given display - */ - fun hideStashedDesktopApps(displayId: Int) { - if (DesktopModeStatus.isStashingEnabled()) { - KtProtoLog.v( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: hideStashedApps displayId=%d", - displayId - ) - desktopModeTaskRepository.setStashed(displayId, false) - } - } - /** Get number of tasks that are marked as visible */ fun getVisibleTaskCount(displayId: Int): Int { return desktopModeTaskRepository.getVisibleTaskCount(displayId) @@ -871,8 +843,6 @@ class DesktopTasksController( val result = triggerTask?.let { task -> when { request.type == TRANSIT_TO_BACK -> handleBackNavigation(task) - // If display has tasks stashed, handle as stashed launch - task.isStashed -> handleStashedTaskLaunch(task, transition) // Check if the task has a top transparent activity shouldLaunchAsModal(task) -> handleTransparentTaskLaunch(task) // Check if fullscreen task should be updated @@ -911,12 +881,8 @@ class DesktopTasksController( .forEach { finishTransaction.setCornerRadius(it.leash, cornerRadius) } } - private val TaskInfo.isStashed: Boolean - get() = desktopModeTaskRepository.isStashed(displayId) - - private fun shouldLaunchAsModal(task: TaskInfo): Boolean { - return Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task) - } + private fun shouldLaunchAsModal(task: TaskInfo) = + Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task) private fun shouldRemoveWallpaper(request: TransitionRequestInfo): Boolean { return Flags.enableDesktopWindowingWallpaperActivity() && @@ -976,24 +942,6 @@ class DesktopTasksController( return null } - private fun handleStashedTaskLaunch( - task: RunningTaskInfo, - transition: IBinder - ): WindowContainerTransaction { - KtProtoLog.d( - WM_SHELL_DESKTOP_MODE, - "DesktopTasksController: launch apps with stashed on transition taskId=%d", - task.taskId - ) - val wct = WindowContainerTransaction() - val taskToMinimize = - bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId) - addMoveToDesktopChanges(wct, task) - desktopModeTaskRepository.setStashed(task.displayId, false) - addPendingMinimizeTransition(transition, taskToMinimize) - return wct - } - // Always launch transparent tasks in fullscreen. private fun handleTransparentTaskLaunch(task: RunningTaskInfo): WindowContainerTransaction? { // Already fullscreen, no-op. @@ -1467,25 +1415,25 @@ class DesktopTasksController( ) { c -> c.showDesktopApps(displayId, remoteTransition) } } - override fun stashDesktopApps(displayId: Int) { + override fun showDesktopApp(taskId: Int) { ExecutorUtils.executeRemoteCallWithTaskPermission( controller, - "stashDesktopApps" - ) { c -> c.stashDesktopApps(displayId) } + "showDesktopApp" + ) { c -> c.moveTaskToFront(taskId) } } - override fun hideStashedDesktopApps(displayId: Int) { - ExecutorUtils.executeRemoteCallWithTaskPermission( - controller, - "hideStashedDesktopApps" - ) { c -> c.hideStashedDesktopApps(displayId) } + override fun stashDesktopApps(displayId: Int) { + KtProtoLog.w( + WM_SHELL_DESKTOP_MODE, + "IDesktopModeImpl: stashDesktopApps is deprecated" + ) } - override fun showDesktopApp(taskId: Int) { - ExecutorUtils.executeRemoteCallWithTaskPermission( - controller, - "showDesktopApp" - ) { c -> c.moveTaskToFront(taskId) } + override fun hideStashedDesktopApps(displayId: Int) { + KtProtoLog.w( + WM_SHELL_DESKTOP_MODE, + "IDesktopModeImpl: hideStashedDesktopApps is deprecated" + ) } override fun getVisibleTaskCount(displayId: Int): Int { 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 fa4352241193..c36f8deb6ecc 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 @@ -28,10 +28,10 @@ interface IDesktopMode { /** Show apps on the desktop on the given display */ void showDesktopApps(int displayId, in RemoteTransition remoteTransition); - /** Stash apps on the desktop to allow launching another app from home screen */ + /** @deprecated use {@link #showDesktopApps} instead. */ void stashDesktopApps(int displayId); - /** Hide apps that may be stashed */ + /** @deprecated this is no longer supported. */ void hideStashedDesktopApps(int displayId); /** Bring task with the given id to front */ diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java index ecb53dc17a48..59d696918448 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java @@ -16,11 +16,11 @@ package com.android.wm.shell.draganddrop; -import static android.app.StatusBarManager.DISABLE2_NONE; import static android.app.StatusBarManager.DISABLE_NONE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS; import static android.content.pm.ActivityInfo.CONFIG_UI_MODE; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; @@ -516,20 +516,18 @@ public class DragLayout extends LinearLayout } private void animateFullscreenContainer(boolean visible) { - int flags = visible ? HIDE_STATUS_BAR_FLAGS : DISABLE_NONE; - StatusBarManager.DisableInfo disableInfo = new StatusBarManager.DisableInfo(flags, - DISABLE2_NONE); - mStatusBarManager.requestDisabledComponent(disableInfo, "animateFullscreenContainer"); + mStatusBarManager.disable(visible + ? HIDE_STATUS_BAR_FLAGS + : DISABLE_NONE); // We're only using the first drop zone if there is one fullscreen target mDropZoneView1.setShowingMargin(visible); mDropZoneView1.setShowingHighlight(visible); } private void animateSplitContainers(boolean visible, Runnable animCompleteCallback) { - int flags = visible ? HIDE_STATUS_BAR_FLAGS : DISABLE_NONE; - StatusBarManager.DisableInfo disableInfo = new StatusBarManager.DisableInfo(flags, - DISABLE2_NONE); - mStatusBarManager.requestDisabledComponent(disableInfo, "animateSplitContainers"); + mStatusBarManager.disable(visible + ? HIDE_STATUS_BAR_FLAGS + : DISABLE_NONE); mDropZoneView1.setShowingMargin(visible); mDropZoneView2.setShowingMargin(visible); Animator animator = mDropZoneView1.getAnimator(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java index 7b1ef5c6cddd..a749019046f8 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java @@ -39,7 +39,7 @@ public interface Pip { * @param isSysUiStateValid Is SysUI state valid or not. * @param flag Current SysUI state. */ - default void onSystemUiStateChanged(boolean isSysUiStateValid, int flag) { + default void onSystemUiStateChanged(boolean isSysUiStateValid, long flag) { } /** 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 139cde2c66f7..85f9194ac804 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 @@ -847,7 +847,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb } } - private void onSystemUiStateChanged(boolean isValidState, int flag) { + private void onSystemUiStateChanged(boolean isValidState, long flag) { mTouchHandler.onSystemUiStateChanged(isValidState); } @@ -1195,7 +1195,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override - public void onSystemUiStateChanged(boolean isSysUiStateValid, int flag) { + public void onSystemUiStateChanged(boolean isSysUiStateValid, long flag) { mMainExecutor.execute(() -> { PipController.this.onSystemUiStateChanged(isSysUiStateValid, flag); }); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java index 03547a55fa27..b757b00f16dd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInputConsumer.java @@ -53,7 +53,7 @@ public class PipInputConsumer { * Listener interface for callers to learn when this class is registered or unregistered with * window manager */ - private interface RegistrationListener { + interface RegistrationListener { void onRegistrationChanged(boolean isRegistered); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java index 619bed4e19ca..a097a0ffa47d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java @@ -31,7 +31,9 @@ import android.annotation.Nullable; import android.content.Context; import android.graphics.PointF; import android.graphics.Rect; +import android.os.Bundle; import android.os.Debug; +import android.view.SurfaceControl; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.R; @@ -39,6 +41,7 @@ import com.android.wm.shell.animation.FloatProperties; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.magnetictarget.MagnetizedObject; import com.android.wm.shell.common.pip.PipAppOpsListener; +import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipPerfHintController; import com.android.wm.shell.common.pip.PipSnapAlgorithm; @@ -57,6 +60,7 @@ import java.util.function.Consumer; public class PipMotionHelper implements PipAppOpsListener.Callback, FloatingContentCoordinator.FloatingContent { private static final String TAG = "PipMotionHelper"; + private static final String FLING_BOUNDS_CHANGE = "fling_bounds_change"; private static final boolean DEBUG = false; private static final int SHRINK_STACK_FROM_MENU_DURATION = 250; @@ -72,7 +76,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private final Context mContext; private @NonNull PipBoundsState mPipBoundsState; - + private @NonNull PipBoundsAlgorithm mPipBoundsAlgorithm; + private @NonNull PipScheduler mPipScheduler; + private @NonNull PipTransitionState mPipTransitionState; private PhonePipMenuController mMenuController; private PipSnapAlgorithm mSnapAlgorithm; @@ -145,6 +151,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private boolean mDismissalPending = false; /** + * Set to true if bounds change transition has been scheduled from PipMotionHelper. + */ + private boolean mWaitingForBoundsChangeTransition = false; + + /** * Gets set in {@link #animateToExpandedState(Rect, Rect, Rect, Runnable)}, this callback is * used to show menu activity when the expand animation is completed. */ @@ -152,22 +163,25 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, public PipMotionHelper(Context context, @NonNull PipBoundsState pipBoundsState, PhonePipMenuController menuController, PipSnapAlgorithm snapAlgorithm, - FloatingContentCoordinator floatingContentCoordinator, - Optional<PipPerfHintController> pipPerfHintControllerOptional) { + FloatingContentCoordinator floatingContentCoordinator, PipScheduler pipScheduler, + Optional<PipPerfHintController> pipPerfHintControllerOptional, + PipBoundsAlgorithm pipBoundsAlgorithm, PipTransitionState pipTransitionState) { mContext = context; mPipBoundsState = pipBoundsState; + mPipBoundsAlgorithm = pipBoundsAlgorithm; + mPipScheduler = pipScheduler; mMenuController = menuController; mSnapAlgorithm = snapAlgorithm; mFloatingContentCoordinator = floatingContentCoordinator; mPipPerfHintController = pipPerfHintControllerOptional.orElse(null); mResizePipUpdateListener = (target, values) -> { if (mPipBoundsState.getMotionBoundsState().isInMotion()) { - /* - mPipTaskOrganizer.scheduleUserResizePip(getBounds(), - mPipBoundsState.getMotionBoundsState().getBoundsInMotion(), null); - */ + mPipScheduler.scheduleUserResizePip( + mPipBoundsState.getMotionBoundsState().getBoundsInMotion()); } }; + mPipTransitionState = pipTransitionState; + mPipTransitionState.addPipTransitionStateChangedListener(this::onPipTransitionStateChanged); } void init() { @@ -236,12 +250,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, mPipBoundsState.setBounds(toBounds); } else { mPipBoundsState.getMotionBoundsState().setBoundsInMotion(toBounds); - /* - mPipTaskOrganizer.scheduleUserResizePip(getBounds(), toBounds, - (Rect newBounds) -> { - mMenuController.updateMenuLayout(newBounds); - }); - */ + mPipScheduler.scheduleUserResizePip(toBounds); } } else { // If PIP is 'catching up' after being stuck in the dismiss target, update the animation @@ -552,11 +561,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, /** Set new fling configs whose min/max values respect the given movement bounds. */ private void rebuildFlingConfigs() { mFlingConfigX = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION, - mPipBoundsState.getMovementBounds().left, - mPipBoundsState.getMovementBounds().right); + mPipBoundsAlgorithm.getMovementBounds(getBounds()).left, + mPipBoundsAlgorithm.getMovementBounds(getBounds()).right); mFlingConfigY = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION, - mPipBoundsState.getMovementBounds().top, - mPipBoundsState.getMovementBounds().bottom); + mPipBoundsAlgorithm.getMovementBounds(getBounds()).top, + mPipBoundsAlgorithm.getMovementBounds(getBounds()).bottom); final Rect insetBounds = mPipBoundsState.getDisplayLayout().stableInsets(); mStashConfigX = new PhysicsAnimator.FlingConfig( DEFAULT_FRICTION, @@ -623,22 +632,15 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private void onBoundsPhysicsAnimationEnd() { // The physics animation ended, though we may not necessarily be done animating, such as // when we're still dragging after moving out of the magnetic target. - if (!mDismissalPending - && !mSpringingToTouch - && !mMagnetizedPip.getObjectStuckToTarget()) { - // All motion operations have actually finished. - mPipBoundsState.setBounds( - mPipBoundsState.getMotionBoundsState().getBoundsInMotion()); - mPipBoundsState.getMotionBoundsState().onAllAnimationsEnded(); - if (!mDismissalPending) { - // do not schedule resize if PiP is dismissing, which may cause app re-open to - // mBounds instead of its normal bounds. - // mPipTaskOrganizer.scheduleFinishResizePip(getBounds()); - } + if (!mDismissalPending && !mSpringingToTouch && !mMagnetizedPip.getObjectStuckToTarget()) { + // do not schedule resize if PiP is dismissing, which may cause app re-open to + // mBounds instead of its normal bounds. + Bundle extra = new Bundle(); + extra.putBoolean(FLING_BOUNDS_CHANGE, true); + mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra); + return; } - mPipBoundsState.getMotionBoundsState().onPhysicsAnimationEnded(); - mSpringingToTouch = false; - mDismissalPending = false; + settlePipBoundsAfterPhysicsAnimation(true /* animatingAfter */); cleanUpHighPerfSessionMaybe(); } @@ -662,7 +664,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, + " callers=\n%s", TAG, toBounds, Debug.getCallers(5, " ")); } if (!toBounds.equals(getBounds())) { - // mPipTaskOrganizer.scheduleResizePip(toBounds, mUpdateBoundsCallback); + mPipScheduler.scheduleAnimateResizePip(toBounds); } } @@ -685,6 +687,60 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // setAnimatingToBounds(toBounds); } + private void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState, + @PipTransitionState.TransitionState int newState, + @Nullable Bundle extra) { + switch (newState) { + case PipTransitionState.SCHEDULED_BOUNDS_CHANGE: + if (!extra.getBoolean(FLING_BOUNDS_CHANGE)) break; + + // If touch is turned off and we are in a fling animation, schedule a transition. + mWaitingForBoundsChangeTransition = true; + mPipScheduler.scheduleAnimateResizePip( + mPipBoundsState.getMotionBoundsState().getBoundsInMotion()); + break; + case PipTransitionState.CHANGING_PIP_BOUNDS: + if (!mWaitingForBoundsChangeTransition) break; + + // If bounds change transition was scheduled from this class, handle leash updates. + mWaitingForBoundsChangeTransition = false; + SurfaceControl.Transaction startTx = extra.getParcelable( + PipTransition.PIP_START_TX, SurfaceControl.Transaction.class); + Rect destinationBounds = extra.getParcelable( + PipTransition.PIP_DESTINATION_BOUNDS, Rect.class); + startTx.setPosition(mPipTransitionState.mPinnedTaskLeash, + destinationBounds.left, destinationBounds.top); + startTx.apply(); + + // All motion operations have actually finished, so make bounds cache updates. + settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */); + cleanUpHighPerfSessionMaybe(); + + // Setting state to CHANGED_PIP_BOUNDS applies finishTx and notifies Core. + mPipTransitionState.setState(PipTransitionState.CHANGED_PIP_BOUNDS); + break; + case PipTransitionState.EXITING_PIP: + // We need to force finish any local animators if about to leave PiP, to avoid + // breaking the state (e.g. leashes are cleaned up upon exit). + if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break; + cancelPhysicsAnimation(); + settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */); + } + } + + private void settlePipBoundsAfterPhysicsAnimation(boolean animatingAfter) { + if (!animatingAfter) { + // The physics animation ended, though we may not necessarily be done animating, such as + // when we're still dragging after moving out of the magnetic target. Only set the final + // bounds state and clear motion bounds completely if the whole animation is over. + mPipBoundsState.setBounds(mPipBoundsState.getMotionBoundsState().getBoundsInMotion()); + mPipBoundsState.getMotionBoundsState().onAllAnimationsEnded(); + } + mPipBoundsState.getMotionBoundsState().onPhysicsAnimationEnded(); + mSpringingToTouch = false; + mDismissalPending = false; + } + /** * Returns a MagnetizedObject wrapper for PIP's animated bounds. This is provided to the * magnetic dismiss target so it can calculate PIP's size and position. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java index 72fa3badeb93..c5b0de31f104 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java @@ -25,16 +25,19 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Rect; +import android.view.SurfaceControl; import android.window.WindowContainerTransaction; import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; +import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipUtils; import com.android.wm.shell.pip.PipTransitionController; +import com.android.wm.shell.protolog.ShellProtoLogGroup; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -156,4 +159,20 @@ public class PipScheduler { wct.setBounds(mPipTransitionState.mPipTaskToken, toBounds); mPipTransitionController.startResizeTransition(wct); } + + /** + * Directly perform a scaled matrix transformation on the leash. This will not perform any + * {@link WindowContainerTransaction}. + */ + public void scheduleUserResizePip(Rect toBounds) { + if (toBounds.isEmpty()) { + ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, + "%s: Attempted to user resize PIP to empty bounds, aborting.", TAG); + return; + } + SurfaceControl leash = mPipTransitionState.mPinnedTaskLeash; + final SurfaceControl.Transaction tx = new SurfaceControl.Transaction(); + tx.setPosition(leash, toBounds.left, toBounds.top); + tx.apply(); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java index 472003cb435f..9c6e3ea494fa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java @@ -16,6 +16,8 @@ package com.android.wm.shell.pip2.phone; +import static android.view.WindowManager.INPUT_CONSUMER_PIP; + import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_STASHING; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.PIP_STASH_MINIMUM_VELOCITY_THRESHOLD; import static com.android.wm.shell.common.pip.PipBoundsState.STASH_TYPE_LEFT; @@ -30,18 +32,19 @@ import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_PICTURE_ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; -import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; +import android.os.Bundle; import android.provider.DeviceConfig; import android.util.Size; import android.view.DisplayCutout; import android.view.InputEvent; import android.view.MotionEvent; import android.view.ViewConfiguration; +import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; @@ -80,6 +83,7 @@ public class PipTouchHandler { private final Context mContext; private final PipBoundsAlgorithm mPipBoundsAlgorithm; @NonNull private final PipBoundsState mPipBoundsState; + @NonNull private final PipTransitionState mPipTransitionState; @NonNull private final SizeSpecSource mSizeSpecSource; private final PipUiEventLogger mPipUiEventLogger; private final PipDismissTargetHandler mPipDismissTargetHandler; @@ -125,6 +129,7 @@ public class PipTouchHandler { private final FloatingContentCoordinator mFloatingContentCoordinator; private PipMotionHelper mMotionHelper; private PipTouchGesture mGesture; + private PipInputConsumer mPipInputConsumer; // Temp vars private final Rect mTmpBounds = new Rect(); @@ -167,6 +172,7 @@ public class PipTouchHandler { PhonePipMenuController menuController, PipBoundsAlgorithm pipBoundsAlgorithm, @NonNull PipBoundsState pipBoundsState, + @NonNull PipTransitionState pipTransitionState, @NonNull SizeSpecSource sizeSpecSource, PipMotionHelper pipMotionHelper, FloatingContentCoordinator floatingContentCoordinator, @@ -179,6 +185,9 @@ public class PipTouchHandler { mAccessibilityManager = context.getSystemService(AccessibilityManager.class); mPipBoundsAlgorithm = pipBoundsAlgorithm; mPipBoundsState = pipBoundsState; + + mPipTransitionState = pipTransitionState; + mPipTransitionState.addPipTransitionStateChangedListener(this::onPipTransitionStateChanged); mSizeSpecSource = sizeSpecSource; mMenuController = menuController; mPipUiEventLogger = pipUiEventLogger; @@ -227,6 +236,11 @@ public class PipTouchHandler { mPipResizeGestureHandler.init(); mPipDismissTargetHandler.init(); + mPipInputConsumer = new PipInputConsumer(WindowManagerGlobal.getWindowManagerService(), + INPUT_CONSUMER_PIP, mMainExecutor); + mPipInputConsumer.setInputListener(this::handleTouchEvent); + mPipInputConsumer.setRegistrationListener(this::onRegistrationChanged); + mEnableStash = DeviceConfig.getBoolean( DeviceConfig.NAMESPACE_SYSTEMUI, PIP_STASHING, @@ -294,19 +308,17 @@ public class PipTouchHandler { void onActivityPinned() { mPipDismissTargetHandler.createOrUpdateDismissTarget(); - mPipResizeGestureHandler.onActivityPinned(); mFloatingContentCoordinator.onContentAdded(mMotionHelper); + mPipInputConsumer.registerInputConsumer(); } - void onActivityUnpinned(ComponentName topPipActivity) { - if (topPipActivity == null) { - // Clean up state after the last PiP activity is removed - mPipDismissTargetHandler.cleanUpDismissTarget(); - - mFloatingContentCoordinator.onContentRemoved(mMotionHelper); - } + void onActivityUnpinned() { + // Clean up state after the last PiP activity is removed + mPipDismissTargetHandler.cleanUpDismissTarget(); + mFloatingContentCoordinator.onContentRemoved(mMotionHelper); mPipResizeGestureHandler.onActivityUnpinned(); + mPipInputConsumer.unregisterInputConsumer(); } void onPinnedStackAnimationEnded( @@ -512,6 +524,7 @@ public class PipTouchHandler { return true; } + /* if ((ev.getAction() == MotionEvent.ACTION_DOWN || mTouchState.isUserInteracting()) && mPipDismissTargetHandler.maybeConsumeMotionEvent(ev)) { // If the first touch event occurs within the magnetic field, pass the ACTION_DOWN event @@ -528,11 +541,13 @@ public class PipTouchHandler { return true; } - if (!mTouchState.isUserInteracting()) { + // Ignore the motion event When the entry animation is waiting to be started + if (!mTouchState.isUserInteracting() && mPipTaskOrganizer.isEntryScheduled()) { ProtoLog.wtf(WM_SHELL_PICTURE_IN_PICTURE, "%s: Waiting to start the entry animation, skip the motion event.", TAG); return true; } + */ // Update the touch state mTouchState.onTouchEvent(ev); @@ -808,7 +823,7 @@ public class PipTouchHandler { mMovementWithinDismiss = touchState.getDownTouchPosition().y >= mPipBoundsState.getMovementBounds().bottom; mMotionHelper.setSpringingToTouch(false); - // mPipDismissTargetHandler.setTaskLeash(mPipTaskOrganizer.getSurfaceControl()); + mPipDismissTargetHandler.setTaskLeash(mPipTransitionState.mPinnedTaskLeash); // If the menu is still visible then just poke the menu // so that it will timeout after the user stops touching it @@ -880,7 +895,8 @@ public class PipTouchHandler { // Reset the touch state on up before the fling settles mTouchState.reset(); if (mEnableStash && shouldStash(vel, getPossiblyMotionBounds())) { - mMotionHelper.stashToEdge(vel.x, vel.y, this::stashEndAction /* endAction */); + // mMotionHelper.stashToEdge(vel.x, vel.y, + // this::stashEndAction /* endAction */); } else { if (mPipBoundsState.isStashed()) { // Reset stashed state if previously stashed @@ -1059,6 +1075,27 @@ public class PipTouchHandler { mPipResizeGestureHandler.setOhmOffset(offset); } + private void onPipTransitionStateChanged(@PipTransitionState.TransitionState int oldState, + @PipTransitionState.TransitionState int newState, + @Nullable Bundle extra) { + switch (newState) { + case PipTransitionState.ENTERED_PIP: + onActivityPinned(); + mTouchState.setAllowInputEvents(true); + break; + case PipTransitionState.EXITED_PIP: + mTouchState.setAllowInputEvents(false); + onActivityUnpinned(); + break; + case PipTransitionState.SCHEDULED_BOUNDS_CHANGE: + mTouchState.setAllowInputEvents(false); + break; + case PipTransitionState.CHANGED_PIP_BOUNDS: + mTouchState.setAllowInputEvents(true); + break; + } + } + /** * Dumps the {@link PipTouchHandler} state. */ 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 8b2d0ddf2510..7dddd2748f83 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 @@ -61,11 +61,15 @@ import com.android.wm.shell.transition.Transitions; public class PipTransition extends PipTransitionController implements PipTransitionState.PipTransitionStateChangedListener { private static final String TAG = PipTransition.class.getSimpleName(); + + // Used when for ENTERING_PIP state update. private static final String PIP_TASK_TOKEN = "pip_task_token"; private static final String PIP_TASK_LEASH = "pip_task_leash"; - private static final String PIP_START_TX = "pip_start_tx"; - private static final String PIP_FINISH_TX = "pip_finish_tx"; - private static final String PIP_DESTINATION_BOUNDS = "pip_dest_bounds"; + + // Used for PiP CHANGING_BOUNDS state update. + static final String PIP_START_TX = "pip_start_tx"; + static final String PIP_FINISH_TX = "pip_finish_tx"; + static final String PIP_DESTINATION_BOUNDS = "pip_dest_bounds"; /** * The fixed start delay in ms when fading out the content overlay from bounds animation. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java index 9a9c59e2fa8e..8204d41a9833 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java @@ -71,17 +71,21 @@ public class PipTransitionState { // State for app finishing drawing in PiP mode as a final step in enter PiP flow. public static final int ENTERED_PIP = 3; - // State for scheduling a transition to change PiP bounds. - public static final int CHANGING_PIP_BOUNDS = 4; + // State to indicate we have scheduled a PiP bounds change transition. + public static final int SCHEDULED_BOUNDS_CHANGE = 4; - // State for app potentially finishing drawing in new PiP bounds after resize is complete. - public static final int CHANGED_PIP_BOUNDS = 5; + // State for the start of playing a transition to change PiP bounds. At this point, WM Core + // is aware of the new PiP bounds, but Shell might still be continuing animating. + public static final int CHANGING_PIP_BOUNDS = 5; + + // State for finishing animating into new PiP bounds after resize is complete. + public static final int CHANGED_PIP_BOUNDS = 6; // State for starting exiting PiP. - public static final int EXITING_PIP = 6; + public static final int EXITING_PIP = 7; // State for finishing exit PiP flow. - public static final int EXITED_PIP = 7; + public static final int EXITED_PIP = 8; private static final int FIRST_CUSTOM_STATE = 1000; @@ -92,6 +96,7 @@ public class PipTransitionState { SWIPING_TO_PIP, ENTERING_PIP, ENTERED_PIP, + SCHEDULED_BOUNDS_CHANGE, CHANGING_PIP_BOUNDS, CHANGED_PIP_BOUNDS, EXITING_PIP, @@ -165,10 +170,11 @@ public class PipTransitionState { * @param extra a bundle passed to the subscribed listeners to resolve/cache extra info. */ public void setState(@TransitionState int state, @Nullable Bundle extra) { - if (state == ENTERING_PIP || state == SWIPING_TO_PIP) { - // Whenever we are entering PiP caller must provide extra state to set as well. + if (state == ENTERING_PIP || state == SWIPING_TO_PIP + || state == SCHEDULED_BOUNDS_CHANGE || state == CHANGING_PIP_BOUNDS) { + // States listed above require extra bundles to be provided. Preconditions.checkArgument(extra != null && !extra.isEmpty(), - "No extra bundle for either ENTERING_PIP or SWIPING_TO_PIP state."); + "No extra bundle for " + stateToString(state) + " state."); } if (mState != state) { dispatchPipTransitionStateChanged(mState, state, extra); @@ -254,23 +260,24 @@ public class PipTransitionState { return ++mPrevCustomState; } - private String stateToString() { - switch (mState) { + private static String stateToString(int state) { + switch (state) { case UNDEFINED: return "undefined"; case SWIPING_TO_PIP: return "swiping_to_pip"; case ENTERING_PIP: return "entering-pip"; case ENTERED_PIP: return "entered-pip"; + case SCHEDULED_BOUNDS_CHANGE: return "scheduled_bounds_change"; case CHANGING_PIP_BOUNDS: return "changing-bounds"; case CHANGED_PIP_BOUNDS: return "changed-bounds"; case EXITING_PIP: return "exiting-pip"; case EXITED_PIP: return "exited-pip"; } - throw new IllegalStateException("Unknown state: " + mState); + throw new IllegalStateException("Unknown state: " + state); } @Override public String toString() { return String.format("PipTransitionState(mState=%s, mInSwipePipToHomeTransition=%b)", - stateToString(), mInSwipePipToHomeTransition); + stateToString(mState), mInSwipePipToHomeTransition); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java index f99b4b2beef0..f6f3aa49bc6e 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java @@ -120,7 +120,7 @@ public class BackAnimationControllerTest extends ShellTestCase { private TestableContentResolver mContentResolver; private TestableLooper mTestableLooper; - private CrossActivityBackAnimation mCrossActivityBackAnimation; + private DefaultCrossActivityBackAnimation mDefaultCrossActivityBackAnimation; private CrossTaskBackAnimation mCrossTaskBackAnimation; private ShellBackAnimationRegistry mShellBackAnimationRegistry; @@ -135,13 +135,14 @@ public class BackAnimationControllerTest extends ShellTestCase { ANIMATION_ENABLED); mTestableLooper = TestableLooper.get(this); mShellInit = spy(new ShellInit(mShellExecutor)); - mCrossActivityBackAnimation = new CrossActivityBackAnimation(mContext, mAnimationBackground, - mRootTaskDisplayAreaOrganizer); + mDefaultCrossActivityBackAnimation = new DefaultCrossActivityBackAnimation(mContext, + mAnimationBackground, mRootTaskDisplayAreaOrganizer); mCrossTaskBackAnimation = new CrossTaskBackAnimation(mContext, mAnimationBackground); mShellBackAnimationRegistry = - new ShellBackAnimationRegistry(mCrossActivityBackAnimation, mCrossTaskBackAnimation, - /* dialogCloseAnimation= */ null, - new CustomizeActivityAnimation(mContext, mAnimationBackground), + new ShellBackAnimationRegistry(mDefaultCrossActivityBackAnimation, + mCrossTaskBackAnimation, /* dialogCloseAnimation= */ null, + new CustomCrossActivityBackAnimation(mContext, mAnimationBackground, + mRootTaskDisplayAreaOrganizer), /* defaultBackToHomeAnimation= */ null); mController = new BackAnimationController( @@ -582,7 +583,7 @@ public class BackAnimationControllerTest extends ShellTestCase { @Test public void testBackToActivity() throws RemoteException { verifySystemBackBehavior(BackNavigationInfo.TYPE_CROSS_ACTIVITY, - mCrossActivityBackAnimation.getRunner()); + mDefaultCrossActivityBackAnimation.getRunner()); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt new file mode 100644 index 000000000000..8bf011192347 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomCrossActivityBackAnimationTest.kt @@ -0,0 +1,264 @@ +/* + * 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.f + */ +package com.android.wm.shell.back + +import android.app.ActivityManager +import android.app.ActivityManager.RunningTaskInfo +import android.app.AppCompatTaskInfo +import android.app.WindowConfiguration +import android.graphics.Color +import android.graphics.Point +import android.graphics.Rect +import android.os.RemoteException +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper +import android.view.Choreographer +import android.view.RemoteAnimationTarget +import android.view.SurfaceControl +import android.view.SurfaceControl.Transaction +import android.view.animation.Animation +import android.window.BackEvent +import android.window.BackMotionEvent +import android.window.BackNavigationInfo +import androidx.test.filters.SmallTest +import com.android.internal.policy.TransitionAnimation +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.ShellTestCase +import java.util.concurrent.CountDownLatch +import java.util.concurrent.TimeUnit +import junit.framework.TestCase.assertEquals +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyBoolean +import org.mockito.ArgumentMatchers.anyFloat +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.eq +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.kotlin.spy +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@SmallTest +@TestableLooper.RunWithLooper +@RunWith(AndroidTestingRunner::class) +class CustomCrossActivityBackAnimationTest : ShellTestCase() { + @Mock private lateinit var backAnimationBackground: BackAnimationBackground + @Mock private lateinit var mockCloseAnimation: Animation + @Mock private lateinit var mockOpenAnimation: Animation + @Mock private lateinit var rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer + @Mock private lateinit var transitionAnimation: TransitionAnimation + @Mock private lateinit var appCompatTaskInfo: AppCompatTaskInfo + @Mock private lateinit var transaction: Transaction + + private lateinit var customCrossActivityBackAnimation: CustomCrossActivityBackAnimation + private lateinit var customAnimationLoader: CustomAnimationLoader + + @Before + @Throws(Exception::class) + fun setUp() { + customAnimationLoader = CustomAnimationLoader(transitionAnimation) + customCrossActivityBackAnimation = + CustomCrossActivityBackAnimation( + context, + backAnimationBackground, + rootTaskDisplayAreaOrganizer, + transaction, + mock(Choreographer::class.java), + customAnimationLoader + ) + + whenever(transitionAnimation.loadAppTransitionAnimation(eq(PACKAGE_NAME), eq(OPEN_RES_ID))) + .thenReturn(mockOpenAnimation) + whenever(transitionAnimation.loadAppTransitionAnimation(eq(PACKAGE_NAME), eq(CLOSE_RES_ID))) + .thenReturn(mockCloseAnimation) + whenever(transaction.setColor(any(), any())).thenReturn(transaction) + whenever(transaction.setAlpha(any(), anyFloat())).thenReturn(transaction) + whenever(transaction.setCrop(any(), any())).thenReturn(transaction) + whenever(transaction.setRelativeLayer(any(), any(), anyInt())).thenReturn(transaction) + spy(customCrossActivityBackAnimation) + } + + @Test + @Throws(InterruptedException::class) + fun receiveFinishAfterInvoke() { + val finishCalled = startCustomAnimation() + try { + customCrossActivityBackAnimation.getRunner().callback.onBackInvoked() + } catch (r: RemoteException) { + Assert.fail("onBackInvoked throw remote exception") + } + finishCalled.await(1, TimeUnit.SECONDS) + } + + @Test + @Throws(InterruptedException::class) + fun receiveFinishAfterCancel() { + val finishCalled = startCustomAnimation() + try { + customCrossActivityBackAnimation.getRunner().callback.onBackCancelled() + } catch (r: RemoteException) { + Assert.fail("onBackCancelled throw remote exception") + } + finishCalled.await(1, TimeUnit.SECONDS) + } + + @Test + @Throws(InterruptedException::class) + fun receiveFinishWithoutAnimationAfterInvoke() { + val finishCalled = startCustomAnimation(targets = arrayOf()) + try { + customCrossActivityBackAnimation.getRunner().callback.onBackInvoked() + } catch (r: RemoteException) { + Assert.fail("onBackInvoked throw remote exception") + } + finishCalled.await(1, TimeUnit.SECONDS) + } + + @Test + fun testLoadCustomAnimation() { + testLoadCustomAnimation(OPEN_RES_ID, CLOSE_RES_ID, 0) + } + + @Test + fun testLoadCustomAnimationNoEnter() { + testLoadCustomAnimation(0, CLOSE_RES_ID, 0) + } + + @Test + fun testLoadWindowAnimations() { + testLoadCustomAnimation(0, 0, 30) + } + + @Test + fun testCustomAnimationHigherThanWindowAnimations() { + testLoadCustomAnimation(OPEN_RES_ID, CLOSE_RES_ID, 30) + } + + private fun testLoadCustomAnimation(enterResId: Int, exitResId: Int, windowAnimations: Int) { + val builder = + BackNavigationInfo.Builder() + .setCustomAnimation(PACKAGE_NAME, enterResId, exitResId, Color.GREEN) + .setWindowAnimations(PACKAGE_NAME, windowAnimations) + val info = builder.build().customAnimationInfo!! + whenever( + transitionAnimation.loadAnimationAttr( + eq(PACKAGE_NAME), + eq(windowAnimations), + anyInt(), + anyBoolean() + ) + ) + .thenReturn(mockCloseAnimation) + whenever(transitionAnimation.loadDefaultAnimationAttr(anyInt(), anyBoolean())) + .thenReturn(mockOpenAnimation) + val result = customAnimationLoader.loadAll(info)!! + if (exitResId != 0) { + if (enterResId == 0) { + verify(transitionAnimation, never()) + .loadAppTransitionAnimation(eq(PACKAGE_NAME), eq(enterResId)) + verify(transitionAnimation).loadDefaultAnimationAttr(anyInt(), anyBoolean()) + } else { + assertEquals(result.enterAnimation, mockOpenAnimation) + } + assertEquals(result.backgroundColor.toLong(), Color.GREEN.toLong()) + assertEquals(result.closeAnimation, mockCloseAnimation) + verify(transitionAnimation, never()) + .loadAnimationAttr(eq(PACKAGE_NAME), anyInt(), anyInt(), anyBoolean()) + } else if (windowAnimations != 0) { + verify(transitionAnimation, times(2)) + .loadAnimationAttr(eq(PACKAGE_NAME), anyInt(), anyInt(), anyBoolean()) + Assert.assertEquals(result.closeAnimation, mockCloseAnimation) + } + } + + private fun startCustomAnimation( + targets: Array<RemoteAnimationTarget> = + arrayOf(createAnimationTarget(false), createAnimationTarget(true)) + ): CountDownLatch { + val backNavigationInfo = + BackNavigationInfo.Builder() + .setCustomAnimation(PACKAGE_NAME, OPEN_RES_ID, CLOSE_RES_ID, /*backgroundColor*/ 0) + .build() + customCrossActivityBackAnimation.prepareNextAnimation( + backNavigationInfo.customAnimationInfo, + 0 + ) + val finishCalled = CountDownLatch(1) + val finishCallback = Runnable { finishCalled.countDown() } + customCrossActivityBackAnimation + .getRunner() + .startAnimation(targets, null, null, finishCallback) + customCrossActivityBackAnimation.runner.callback.onBackStarted(backMotionEventFrom(0f, 0f)) + if (targets.isNotEmpty()) { + verify(mockCloseAnimation) + .initialize(eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE)) + verify(mockOpenAnimation) + .initialize(eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE), eq(BOUND_SIZE)) + } + return finishCalled + } + + private fun backMotionEventFrom(touchX: Float, progress: Float) = + BackMotionEvent( + /* touchX = */ touchX, + /* touchY = */ 0f, + /* progress = */ progress, + /* velocityX = */ 0f, + /* velocityY = */ 0f, + /* triggerBack = */ false, + /* swipeEdge = */ BackEvent.EDGE_LEFT, + /* departingAnimationTarget = */ null + ) + + private fun createAnimationTarget(open: Boolean): RemoteAnimationTarget { + val topWindowLeash = SurfaceControl() + val taskInfo = RunningTaskInfo() + taskInfo.appCompatTaskInfo = appCompatTaskInfo + taskInfo.taskDescription = ActivityManager.TaskDescription() + return RemoteAnimationTarget( + 1, + if (open) RemoteAnimationTarget.MODE_OPENING else RemoteAnimationTarget.MODE_CLOSING, + topWindowLeash, + false, + Rect(), + Rect(), + -1, + Point(0, 0), + Rect(0, 0, BOUND_SIZE, BOUND_SIZE), + Rect(), + WindowConfiguration(), + true, + null, + null, + taskInfo, + false, + -1 + ) + } + + companion object { + private const val BOUND_SIZE = 100 + private const val OPEN_RES_ID = 1000 + private const val CLOSE_RES_ID = 1001 + private const val PACKAGE_NAME = "TestPackage" + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java deleted file mode 100644 index 158d640dca30..000000000000 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/CustomizeActivityAnimationTest.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * 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.wm.shell.back; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -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.verify; - -import android.app.WindowConfiguration; -import android.graphics.Color; -import android.graphics.Point; -import android.graphics.Rect; -import android.os.RemoteException; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; -import android.view.Choreographer; -import android.view.RemoteAnimationTarget; -import android.view.SurfaceControl; -import android.view.animation.Animation; -import android.window.BackNavigationInfo; - -import androidx.test.filters.SmallTest; - -import com.android.wm.shell.ShellTestCase; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -@SmallTest -@TestableLooper.RunWithLooper -@RunWith(AndroidTestingRunner.class) -public class CustomizeActivityAnimationTest extends ShellTestCase { - private static final int BOUND_SIZE = 100; - @Mock - private BackAnimationBackground mBackAnimationBackground; - @Mock - private Animation mMockCloseAnimation; - @Mock - private Animation mMockOpenAnimation; - - private CustomizeActivityAnimation mCustomizeActivityAnimation; - - @Before - public void setUp() throws Exception { - mCustomizeActivityAnimation = new CustomizeActivityAnimation(mContext, - mBackAnimationBackground, mock(SurfaceControl.Transaction.class), - mock(Choreographer.class)); - spyOn(mCustomizeActivityAnimation); - spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation); - } - - RemoteAnimationTarget createAnimationTarget(boolean open) { - SurfaceControl topWindowLeash = new SurfaceControl(); - return new RemoteAnimationTarget(1, - open ? RemoteAnimationTarget.MODE_OPENING : RemoteAnimationTarget.MODE_CLOSING, - topWindowLeash, false, new Rect(), new Rect(), -1, - new Point(0, 0), new Rect(0, 0, BOUND_SIZE, BOUND_SIZE), new Rect(), - new WindowConfiguration(), true, null, null, null, false, -1); - } - - @Test - public void receiveFinishAfterInvoke() throws InterruptedException { - spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader); - doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader) - .loadAnimation(any(), eq(false)); - doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader) - .loadAnimation(any(), eq(true)); - - mCustomizeActivityAnimation.prepareNextAnimation( - new BackNavigationInfo.CustomAnimationInfo("TestPackage"), 0); - final RemoteAnimationTarget close = createAnimationTarget(false); - final RemoteAnimationTarget open = createAnimationTarget(true); - // start animation with remote animation targets - final CountDownLatch finishCalled = new CountDownLatch(1); - final Runnable finishCallback = finishCalled::countDown; - mCustomizeActivityAnimation - .getRunner() - .startAnimation( - new RemoteAnimationTarget[] {close, open}, null, null, finishCallback); - verify(mMockCloseAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE), - eq(BOUND_SIZE), eq(BOUND_SIZE)); - verify(mMockOpenAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE), - eq(BOUND_SIZE), eq(BOUND_SIZE)); - - try { - mCustomizeActivityAnimation.getRunner().getCallback().onBackInvoked(); - } catch (RemoteException r) { - fail("onBackInvoked throw remote exception"); - } - verify(mCustomizeActivityAnimation).onGestureCommitted(); - finishCalled.await(1, TimeUnit.SECONDS); - } - - @Test - public void receiveFinishAfterCancel() throws InterruptedException { - spyOn(mCustomizeActivityAnimation.mCustomAnimationLoader); - doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader) - .loadAnimation(any(), eq(false)); - doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader) - .loadAnimation(any(), eq(true)); - - mCustomizeActivityAnimation.prepareNextAnimation( - new BackNavigationInfo.CustomAnimationInfo("TestPackage"), 0); - final RemoteAnimationTarget close = createAnimationTarget(false); - final RemoteAnimationTarget open = createAnimationTarget(true); - // start animation with remote animation targets - final CountDownLatch finishCalled = new CountDownLatch(1); - final Runnable finishCallback = finishCalled::countDown; - mCustomizeActivityAnimation - .getRunner() - .startAnimation( - new RemoteAnimationTarget[] {close, open}, null, null, finishCallback); - verify(mMockCloseAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE), - eq(BOUND_SIZE), eq(BOUND_SIZE)); - verify(mMockOpenAnimation).initialize(eq(BOUND_SIZE), eq(BOUND_SIZE), - eq(BOUND_SIZE), eq(BOUND_SIZE)); - - try { - mCustomizeActivityAnimation.getRunner().getCallback().onBackCancelled(); - } catch (RemoteException r) { - fail("onBackCancelled throw remote exception"); - } - finishCalled.await(1, TimeUnit.SECONDS); - } - - @Test - public void receiveFinishWithoutAnimationAfterInvoke() throws InterruptedException { - mCustomizeActivityAnimation.prepareNextAnimation( - new BackNavigationInfo.CustomAnimationInfo("TestPackage"), 0); - // start animation without any remote animation targets - final CountDownLatch finishCalled = new CountDownLatch(1); - final Runnable finishCallback = finishCalled::countDown; - mCustomizeActivityAnimation - .getRunner() - .startAnimation(new RemoteAnimationTarget[] {}, null, null, finishCallback); - - try { - mCustomizeActivityAnimation.getRunner().getCallback().onBackInvoked(); - } catch (RemoteException r) { - fail("onBackInvoked throw remote exception"); - } - verify(mCustomizeActivityAnimation).onGestureCommitted(); - finishCalled.await(1, TimeUnit.SECONDS); - } - - @Test - public void testLoadCustomAnimation() { - testLoadCustomAnimation(10, 20, 0); - } - - @Test - public void testLoadCustomAnimationNoEnter() { - testLoadCustomAnimation(0, 10, 0); - } - - @Test - public void testLoadWindowAnimations() { - testLoadCustomAnimation(0, 0, 30); - } - - @Test - public void testCustomAnimationHigherThanWindowAnimations() { - testLoadCustomAnimation(10, 20, 30); - } - - private void testLoadCustomAnimation(int enterResId, int exitResId, int windowAnimations) { - final String testPackage = "TestPackage"; - BackNavigationInfo.Builder builder = new BackNavigationInfo.Builder() - .setCustomAnimation(testPackage, enterResId, exitResId, Color.GREEN) - .setWindowAnimations(testPackage, windowAnimations); - final BackNavigationInfo.CustomAnimationInfo info = builder.build() - .getCustomAnimationInfo(); - - doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader - .mTransitionAnimation) - .loadAppTransitionAnimation(eq(testPackage), eq(enterResId)); - doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader - .mTransitionAnimation) - .loadAppTransitionAnimation(eq(testPackage), eq(exitResId)); - doReturn(mMockCloseAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader - .mTransitionAnimation) - .loadAnimationAttr(eq(testPackage), eq(windowAnimations), anyInt(), anyBoolean()); - doReturn(mMockOpenAnimation).when(mCustomizeActivityAnimation.mCustomAnimationLoader - .mTransitionAnimation).loadDefaultAnimationAttr(anyInt(), anyBoolean()); - - CustomizeActivityAnimation.AnimationLoadResult result = - mCustomizeActivityAnimation.mCustomAnimationLoader.loadAll(info); - - if (exitResId != 0) { - if (enterResId == 0) { - verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation, - never()).loadAppTransitionAnimation(eq(testPackage), eq(enterResId)); - verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation) - .loadDefaultAnimationAttr(anyInt(), anyBoolean()); - } else { - assertEquals(result.mEnterAnimation, mMockOpenAnimation); - } - assertEquals(result.mBackgroundColor, Color.GREEN); - assertEquals(result.mCloseAnimation, mMockCloseAnimation); - verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation, never()) - .loadAnimationAttr(eq(testPackage), anyInt(), anyInt(), anyBoolean()); - } else if (windowAnimations != 0) { - verify(mCustomizeActivityAnimation.mCustomAnimationLoader.mTransitionAnimation, - times(2)).loadAnimationAttr(eq(testPackage), anyInt(), anyInt(), anyBoolean()); - assertEquals(result.mCloseAnimation, mMockCloseAnimation); - } - } -} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java index afae653f0682..9c008647104a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java @@ -668,6 +668,18 @@ public class CompatUIControllerTest extends ShellTestCase { Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton()); } + @Test + public void testLetterboxEduLayout_notCreatedWhenLetterboxEducationIsDisabled() { + TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, + CAMERA_COMPAT_CONTROL_HIDDEN); + taskInfo.appCompatTaskInfo.isLetterboxEducationEnabled = false; + + mController.onCompatInfoChanged(taskInfo, mMockTaskListener); + + verify(mController, never()).createLetterboxEduWindowManager(any(), eq(taskInfo), + eq(mMockTaskListener)); + } + private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat, @CameraCompatControlState int cameraCompatControlState) { return createTaskInfo(displayId, taskId, hasSizeCompat, cameraCompatControlState, @@ -694,6 +706,8 @@ public class CompatUIControllerTest extends ShellTestCase { taskInfo.isVisible = isVisible; taskInfo.isFocused = isFocused; taskInfo.isTopActivityTransparent = isTopActivityTransparent; + taskInfo.appCompatTaskInfo.isLetterboxEducationEnabled = true; + taskInfo.appCompatTaskInfo.topActivityBoundsLetterboxed = true; return taskInfo; } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt index dca7be12fffc..8f59f30da697 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt @@ -182,18 +182,6 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun addListener_notifiesStashed() { - repo.setStashed(DEFAULT_DISPLAY, true) - val listener = TestVisibilityListener() - val executor = TestShellExecutor() - repo.addVisibleTasksListener(listener, executor) - executor.flushAll() - - assertThat(listener.stashedOnDefaultDisplay).isTrue() - assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(1) - } - - @Test fun addListener_tasksOnDifferentDisplay_doesNotNotify() { repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 1, visible = true) val listener = TestVisibilityListener() @@ -400,65 +388,6 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test - fun setStashed_stateIsUpdatedForTheDisplay() { - repo.setStashed(DEFAULT_DISPLAY, true) - assertThat(repo.isStashed(DEFAULT_DISPLAY)).isTrue() - assertThat(repo.isStashed(SECOND_DISPLAY)).isFalse() - - repo.setStashed(DEFAULT_DISPLAY, false) - assertThat(repo.isStashed(DEFAULT_DISPLAY)).isFalse() - } - - @Test - fun setStashed_notifyListener() { - val listener = TestVisibilityListener() - val executor = TestShellExecutor() - repo.addVisibleTasksListener(listener, executor) - repo.setStashed(DEFAULT_DISPLAY, true) - executor.flushAll() - assertThat(listener.stashedOnDefaultDisplay).isTrue() - assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(1) - - repo.setStashed(DEFAULT_DISPLAY, false) - executor.flushAll() - assertThat(listener.stashedOnDefaultDisplay).isFalse() - assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(2) - } - - @Test - fun setStashed_secondCallDoesNotNotify() { - val listener = TestVisibilityListener() - val executor = TestShellExecutor() - repo.addVisibleTasksListener(listener, executor) - repo.setStashed(DEFAULT_DISPLAY, true) - repo.setStashed(DEFAULT_DISPLAY, true) - executor.flushAll() - assertThat(listener.stashedChangesOnDefaultDisplay).isEqualTo(1) - } - - @Test - fun setStashed_tracksPerDisplay() { - val listener = TestVisibilityListener() - val executor = TestShellExecutor() - repo.addVisibleTasksListener(listener, executor) - - repo.setStashed(DEFAULT_DISPLAY, true) - executor.flushAll() - assertThat(listener.stashedOnDefaultDisplay).isTrue() - assertThat(listener.stashedOnSecondaryDisplay).isFalse() - - repo.setStashed(SECOND_DISPLAY, true) - executor.flushAll() - assertThat(listener.stashedOnDefaultDisplay).isTrue() - assertThat(listener.stashedOnSecondaryDisplay).isTrue() - - repo.setStashed(DEFAULT_DISPLAY, false) - executor.flushAll() - assertThat(listener.stashedOnDefaultDisplay).isFalse() - assertThat(listener.stashedOnSecondaryDisplay).isTrue() - } - - @Test fun removeFreeformTask_removesTaskBoundsBeforeMaximize() { val taskId = 1 repo.saveBoundsBeforeMaximize(taskId, Rect(0, 0, 200, 200)) @@ -598,12 +527,6 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { var visibleChangesOnDefaultDisplay = 0 var visibleChangesOnSecondaryDisplay = 0 - var stashedOnDefaultDisplay = false - var stashedOnSecondaryDisplay = false - - var stashedChangesOnDefaultDisplay = 0 - var stashedChangesOnSecondaryDisplay = 0 - override fun onTasksVisibilityChanged(displayId: Int, visibleTasksCount: Int) { when (displayId) { DEFAULT_DISPLAY -> { @@ -617,20 +540,6 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { else -> fail("Visible task listener received unexpected display id: $displayId") } } - - override fun onStashedChanged(displayId: Int, stashed: Boolean) { - when (displayId) { - DEFAULT_DISPLAY -> { - stashedOnDefaultDisplay = stashed - stashedChangesOnDefaultDisplay++ - } - SECOND_DISPLAY -> { - stashedOnSecondaryDisplay = stashed - stashedChangesOnDefaultDisplay++ - } - else -> fail("Visible task listener received unexpected display id: $displayId") - } - } } companion object { 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 3f76c4f556f7..7e55628b5641 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 @@ -1044,29 +1044,6 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) - fun handleRequest_fullscreenTask_desktopStashed_returnWCTWithAllAppsBroughtToFront() { - assumeTrue(ENABLE_SHELL_TRANSITIONS) - whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true) - - val stashedFreeformTask = setUpFreeformTask(DEFAULT_DISPLAY) - markTaskHidden(stashedFreeformTask) - - val fullscreenTask = createFullscreenTask(DEFAULT_DISPLAY) - - controller.stashDesktopApps(DEFAULT_DISPLAY) - - val result = controller.handleRequest(Binder(), createTransition(fullscreenTask)) - assertThat(result).isNotNull() - result!!.assertReorderSequence(stashedFreeformTask, fullscreenTask) - assertThat(result.changes[fullscreenTask.token.asBinder()]?.windowingMode) - .isEqualTo(WINDOWING_MODE_FREEFORM) - - // Stashed state should be cleared - assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isFalse() - } - - @Test fun handleRequest_freeformTask_freeformVisible_returnNull() { assumeTrue(ENABLE_SHELL_TRANSITIONS) @@ -1133,27 +1110,6 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY) - fun handleRequest_freeformTask_desktopStashed_returnWCTWithAllAppsBroughtToFront() { - assumeTrue(ENABLE_SHELL_TRANSITIONS) - whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true) - - val stashedFreeformTask = setUpFreeformTask(DEFAULT_DISPLAY) - markTaskHidden(stashedFreeformTask) - - val freeformTask = createFreeformTask(DEFAULT_DISPLAY) - - controller.stashDesktopApps(DEFAULT_DISPLAY) - - val result = controller.handleRequest(Binder(), createTransition(freeformTask)) - assertThat(result).isNotNull() - result?.assertReorderSequence(stashedFreeformTask, freeformTask) - - // Stashed state should be cleared - assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isFalse() - } - - @Test fun handleRequest_notOpenOrToFrontTransition_returnNull() { assumeTrue(ENABLE_SHELL_TRANSITIONS) @@ -1269,29 +1225,6 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - fun stashDesktopApps_stateUpdates() { - whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true) - - controller.stashDesktopApps(DEFAULT_DISPLAY) - - assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isTrue() - assertThat(desktopModeTaskRepository.isStashed(SECOND_DISPLAY)).isFalse() - } - - @Test - fun hideStashedDesktopApps_stateUpdates() { - whenever(DesktopModeStatus.isStashingEnabled()).thenReturn(true) - - desktopModeTaskRepository.setStashed(DEFAULT_DISPLAY, true) - desktopModeTaskRepository.setStashed(SECOND_DISPLAY, true) - controller.hideStashedDesktopApps(DEFAULT_DISPLAY) - - assertThat(desktopModeTaskRepository.isStashed(DEFAULT_DISPLAY)).isFalse() - // Check that second display is not affected - assertThat(desktopModeTaskRepository.isStashed(SECOND_DISPLAY)).isTrue() - } - - @Test fun desktopTasksVisibilityChange_visible_setLaunchAdjacentDisabled() { val task = setUpFreeformTask() clearInvocations(launchAdjacentController) diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp b/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp index b511244c4a30..619658923865 100644 --- a/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp +++ b/libs/androidfw/fuzz/resourcefile_fuzzer/Android.bp @@ -19,6 +19,7 @@ package { // to get the below license kinds: // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["frameworks_base_libs_androidfw_license"], + default_team: "trendy_team_android_resources", } cc_fuzz { @@ -31,7 +32,7 @@ cc_fuzz { static_libs: ["libgmock"], target: { android: { - shared_libs:[ + shared_libs: [ "libandroidfw", "libbase", "libcutils", @@ -52,4 +53,15 @@ cc_fuzz { ], }, }, + fuzz_config: { + cc: [ + "android-resources@google.com", + ], + componentid: 568761, + description: "The fuzzer targets the APIs of libandroidfw", + vector: "local_no_privileges_required", + service_privilege: "privileged", + users: "multi_user", + fuzzed_code_usage: "shipped", + }, } diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp index 5cf5a1d00815..f1ee3256dbee 100644 --- a/libs/input/MouseCursorController.cpp +++ b/libs/input/MouseCursorController.cpp @@ -467,10 +467,10 @@ void MouseCursorController::startAnimationLocked() REQUIRES(mLock) { std::function<bool(nsecs_t)> func = std::bind(&MouseCursorController::doAnimations, this, _1); /* - * Using ui::ADISPLAY_ID_NONE for displayId here to avoid removing the callback + * Using ui::LogicalDisplayId::INVALID for displayId here to avoid removing the callback * if a TouchSpotController with the same display is removed. */ - mContext.addAnimationCallback(ui::ADISPLAY_ID_NONE, func); + mContext.addAnimationCallback(ui::LogicalDisplayId::INVALID, func); } } // namespace android diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h index 70e5c2455d81..c6430f7f36ff 100644 --- a/libs/input/PointerController.h +++ b/libs/input/PointerController.h @@ -109,7 +109,7 @@ private: struct Locked { Presentation presentation; - ui::LogicalDisplayId pointerDisplayId = ui::ADISPLAY_ID_NONE; + ui::LogicalDisplayId pointerDisplayId = ui::LogicalDisplayId::INVALID; std::vector<gui::DisplayInfo> mDisplayInfos; std::unordered_map<ui::LogicalDisplayId, TouchSpotController> spotControllers; diff --git a/libs/input/SpriteController.h b/libs/input/SpriteController.h index 070c90c372ff..e147c567ae2d 100644 --- a/libs/input/SpriteController.h +++ b/libs/input/SpriteController.h @@ -174,7 +174,7 @@ private: int32_t layer{0}; float alpha{1.0f}; SpriteTransformationMatrix transformationMatrix; - ui::LogicalDisplayId displayId{ui::ADISPLAY_ID_DEFAULT}; + ui::LogicalDisplayId displayId{ui::LogicalDisplayId::DEFAULT}; sp<SurfaceControl> surfaceControl; int32_t surfaceWidth{0}; diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp index 7a133801f514..2dcb1f1d1650 100644 --- a/libs/input/tests/PointerController_test.cpp +++ b/libs/input/tests/PointerController_test.cpp @@ -166,7 +166,7 @@ protected: PointerControllerTest(); ~PointerControllerTest(); - void ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId = ui::ADISPLAY_ID_DEFAULT); + void ensureDisplayViewportIsSet(ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT); sp<MockSprite> mPointerSprite; sp<MockPointerControllerPolicyInterface> mPolicy; @@ -335,23 +335,23 @@ TEST_F(PointerControllerTest, updatesSkipScreenshotFlagForTouchSpots) { // Update spots to sync state with sprite mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits, - ui::ADISPLAY_ID_DEFAULT); + ui::LogicalDisplayId::DEFAULT); testing::Mock::VerifyAndClearExpectations(testSpotSprite.get()); // Marking the display to skip screenshot should update sprite as well - mPointerController->setSkipScreenshot(ui::ADISPLAY_ID_DEFAULT, true); + mPointerController->setSkipScreenshot(ui::LogicalDisplayId::DEFAULT, true); EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(true)); // Update spots to sync state with sprite mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits, - ui::ADISPLAY_ID_DEFAULT); + ui::LogicalDisplayId::DEFAULT); testing::Mock::VerifyAndClearExpectations(testSpotSprite.get()); // Reset flag and verify again - mPointerController->setSkipScreenshot(ui::ADISPLAY_ID_DEFAULT, false); + mPointerController->setSkipScreenshot(ui::LogicalDisplayId::DEFAULT, false); EXPECT_CALL(*testSpotSprite, setSkipScreenshot).With(testing::Args<0>(false)); mPointerController->setSpots(&testSpotCoords, testIdToIndex.cbegin(), testIdBits, - ui::ADISPLAY_ID_DEFAULT); + ui::LogicalDisplayId::DEFAULT); testing::Mock::VerifyAndClearExpectations(testSpotSprite.get()); } diff --git a/nfc/api/current.txt b/nfc/api/current.txt index 6d4cc3a9ca44..cf7aea405756 100644 --- a/nfc/api/current.txt +++ b/nfc/api/current.txt @@ -64,8 +64,10 @@ package android.nfc { } public final class NfcAdapter { + method @FlaggedApi("android.nfc.nfc_state_change") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(); method public void disableForegroundDispatch(android.app.Activity); method public void disableReaderMode(android.app.Activity); + method @FlaggedApi("android.nfc.nfc_state_change") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable(); method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]); method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle); method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context); diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index 310130e59bfe..a33e2252019b 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -3,9 +3,7 @@ package android.nfc { public final class NfcAdapter { method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable(); method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean); method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState(); diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java index e43d10422729..06098deb8aff 100644 --- a/nfc/java/android/nfc/NfcAdapter.java +++ b/nfc/java/android/nfc/NfcAdapter.java @@ -1106,6 +1106,9 @@ public final class NfcAdapter { * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the * operation is complete. * + * <p>This API is only allowed to be called by system apps + * or apps which are Device Owner or Profile Owner. + * * <p>If this returns true, then either NFC is already on, or * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent * to indicate a state transition. If this returns false, then @@ -1113,9 +1116,8 @@ public final class NfcAdapter { * NFC on (for example we are in airplane mode and NFC is not * toggleable in airplane mode on this platform). * - * @hide */ - @SystemApi + @FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE) @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable() { try { @@ -1146,15 +1148,17 @@ public final class NfcAdapter { * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the * operation is complete. * + * <p>This API is only allowed to be called by system apps + * or apps which are Device Owner or Profile Owner. + * * <p>If this returns true, then either NFC is already off, or * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent * to indicate a state transition. If this returns false, then * there is some problem that prevents an attempt to turn * NFC off. * - * @hide */ - @SystemApi + @FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE) @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable() { try { diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig index 73b29db0f317..cb2a48c2913f 100644 --- a/nfc/java/android/nfc/flags.aconfig +++ b/nfc/java/android/nfc/flags.aconfig @@ -93,3 +93,11 @@ flag { description: "Enable NFC OEM extension support" bug: "331206243" } + +flag { + name: "nfc_state_change" + is_exported: true + namespace: "nfc" + description: "Enable nfc state change API" + bug: "319934052" +} diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml index a33e0dc25d8a..7015c50071a9 100644 --- a/packages/CompanionDeviceManager/res/values-fr/strings.xml +++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml @@ -38,7 +38,7 @@ <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string> <string name="helper_summary_computer" msgid="8774832742608187072">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DISPLAY_NAME">%2$s</xliff:g> pour accéder aux photos, contenus multimédias et notifications de votre téléphone"</string> <string name="title_nearby_device_streaming" msgid="7269956847378799794">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à effectuer cette action ?"</string> - <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à caster les applications et les fonctionnalités système de votre téléphone ?"</string> + <string name="title_nearby_device_streaming_with_mirroring" msgid="242855799919611657">"Autoriser <strong><xliff:g id="DEVICE_NAME">%1$s</xliff:g></strong> à streamer les applications et les fonctionnalités système de votre téléphone ?"</string> <string name="summary_nearby_device_streaming" msgid="4039565463149145573">"%1$s aura accès à tout ce qui est visible ou lu sur le téléphone, y compris les contenus audio, les photos, les informations de paiement, les mots de passe et les messages.<br/><br/>%1$s pourra caster des applications et des fonctionnalités système jusqu\'à ce que vous supprimiez l\'accès à cette autorisation."</string> <string name="helper_summary_nearby_device_streaming" msgid="2063965070936844876">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_NAME">%2$s</xliff:g> de diffuser des applis et d\'autres fonctionnalités système en streaming sur des appareils à proximité"</string> <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string> diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml index 4985ae3cde34..c929ee4dc991 100644 --- a/packages/CompanionDeviceManager/res/values-hu/strings.xml +++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml @@ -54,7 +54,7 @@ <string name="vendor_header_button_description" msgid="7994879208461111473">"További információ"</string> <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string> <string name="permission_sms" msgid="6337141296535774786">"SMS"</string> - <string name="permission_contacts" msgid="3858319347208004438">"Címtár"</string> + <string name="permission_contacts" msgid="3858319347208004438">"Névjegyek"</string> <string name="permission_calendar" msgid="6805668388691290395">"Naptár"</string> <string name="permission_microphone" msgid="2152206421428732949">"Mikrofon"</string> <string name="permission_call_logs" msgid="5546761417694586041">"Hívásnaplók"</string> diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml index ef27359946b3..f74990925332 100644 --- a/packages/CredentialManager/res/values-es-rUS/strings.xml +++ b/packages/CredentialManager/res/values-es-rUS/strings.xml @@ -91,7 +91,7 @@ <string name="no_sign_in_info_in" msgid="2641118151920288356">"No hay información de acceso en <xliff:g id="SOURCE">%1$s</xliff:g>"</string> <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Administrar accesos"</string> <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Desde otro dispositivo"</string> - <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otra voz"</string> + <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otro dispositivo"</string> <string name="request_cancelled_by" msgid="3735222326886267820">"<xliff:g id="APP_NAME">%1$s</xliff:g> canceló la solicitud"</string> <string name="dropdown_presentation_more_sign_in_options_text" msgid="1693727354272417902">"Opciones de acceso"</string> <string name="more_options_content_description" msgid="1323427365788198808">"Más"</string> diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml index e3a9191ab225..9885a1f8fa62 100644 --- a/packages/CredentialManager/res/values-or/strings.xml +++ b/packages/CredentialManager/res/values-or/strings.xml @@ -57,9 +57,9 @@ <string name="set_as_default" msgid="4415328591568654603">"ଡିଫଲ୍ଟ ଭାବେ ସେଟ କରନ୍ତୁ"</string> <string name="settings" msgid="6536394145760913145">"ସେଟିଂସ"</string> <string name="use_once" msgid="9027366575315399714">"ଥରେ ବ୍ୟବହାର କରନ୍ତୁ"</string> - <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ଟି ପାସୱାର୍ଡ • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>ଟି ପାସକୀ"</string> - <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ଟି ପାସୱାର୍ଡ"</string> - <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>ଟି ପାସକୀ"</string> + <string name="more_options_usage_passwords_passkeys" msgid="3470113942332934279">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ପାସୱାର୍ଡ • <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ପାସକୀ"</string> + <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ପାସୱାର୍ଡ"</string> + <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> ପାସକୀ"</string> <string name="more_options_usage_credentials" msgid="1785697001787193984">"<xliff:g id="TOTALCREDENTIALSNUMBER">%1$s</xliff:g>ଟି କ୍ରେଡେନସିଆଲ"</string> <string name="passkey_before_subtitle" msgid="2448119456208647444">"ପାସକୀ"</string> <string name="another_device" msgid="5147276802037801217">"ଅନ୍ୟ ଏକ ଡିଭାଇସ"</string> diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml index 44f5eaa543b3..c6ac74358be4 100644 --- a/packages/CredentialManager/res/values-zh-rHK/strings.xml +++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml @@ -74,7 +74,7 @@ <string name="get_dialog_description_single_tap" msgid="2797059565126030879">"使用螢幕鎖定方式以 <xliff:g id="USERNAME">%2$s</xliff:g> 登入 <xliff:g id="APP_NAME">%1$s</xliff:g>"</string> <string name="get_dialog_title_unlock_options_for" msgid="7096423827682163270">"解鎖 <xliff:g id="APP_NAME">%1$s</xliff:g> 的登入選項"</string> <string name="get_dialog_title_choose_passkey_for" msgid="9175997688078538490">"選擇已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」密鑰"</string> - <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"選擇已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」密碼"</string> + <string name="get_dialog_title_choose_password_for" msgid="1724435823820819221">"選擇「<xliff:g id="APP_NAME">%1$s</xliff:g>」的儲存密碼"</string> <string name="get_dialog_title_choose_saved_sign_in_for" msgid="2420298653461652728">"選擇已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資料"</string> <string name="get_dialog_title_choose_sign_in_for" msgid="645728947702442421">"選擇使用 <xliff:g id="APP_NAME">%1$s</xliff:g> 的帳戶"</string> <string name="get_dialog_title_choose_option_for" msgid="4976380044745029107">"要選擇適用於「<xliff:g id="APP_NAME">%1$s</xliff:g>」的項目嗎?"</string> diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index 25ac3c9d9074..635dc420f18c 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -172,7 +172,7 @@ public class DynamicSystemInstallationService extends Service // This is for testing only now private boolean mEnableWhenCompleted; - private boolean mOneShot; + private boolean mOneShot = true; private boolean mHideNotification; private InstallationAsyncTask.Progress mInstallTaskProgress; diff --git a/packages/PrintSpooler/res/values-night/themes.xml b/packages/PrintSpooler/res/values-night/themes.xml index 3cc64a6ef266..76fa7b921e77 100644 --- a/packages/PrintSpooler/res/values-night/themes.xml +++ b/packages/PrintSpooler/res/values-night/themes.xml @@ -24,6 +24,7 @@ <style name="Theme.SelectPrinterActivity" parent="android:style/Theme.DeviceDefault"> <item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item> + <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> </style> <style name="Theme.PrintActivity" parent="@android:style/Theme.DeviceDefault"> diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml index bd9602540878..22842f724036 100644 --- a/packages/PrintSpooler/res/values/themes.xml +++ b/packages/PrintSpooler/res/values/themes.xml @@ -24,6 +24,7 @@ parent="android:style/Theme.DeviceDefault.Light"> <item name="android:textAppearanceListItemSecondary">@style/ListItemSecondary</item> <item name="android:windowLightStatusBar">true</item> + <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> </style> <style name="Theme.PrintActivity" parent="@android:style/Theme.DeviceDefault.Light"> diff --git a/packages/SettingsLib/IllustrationPreference/Android.bp b/packages/SettingsLib/IllustrationPreference/Android.bp index 6407810367cf..c3a91a20c339 100644 --- a/packages/SettingsLib/IllustrationPreference/Android.bp +++ b/packages/SettingsLib/IllustrationPreference/Android.bp @@ -21,6 +21,7 @@ android_library { "SettingsLibColor", "androidx.preference_preference", "lottie", + "settingslib_illustrationpreference_flags_lib", ], sdk_version: "system_current", @@ -31,3 +32,24 @@ android_library { "com.android.permission", ], } + +aconfig_declarations { + name: "settingslib_illustrationpreference_flags", + package: "com.android.settingslib.widget.flags", + container: "system", + srcs: [ + "aconfig/illustrationpreference.aconfig", + ], +} + +java_aconfig_library { + name: "settingslib_illustrationpreference_flags_lib", + aconfig_declarations: "settingslib_illustrationpreference_flags", + + min_sdk_version: "30", + + apex_available: [ + "//apex_available:platform", + "com.android.permission", + ], +} diff --git a/packages/SettingsLib/IllustrationPreference/aconfig/illustrationpreference.aconfig b/packages/SettingsLib/IllustrationPreference/aconfig/illustrationpreference.aconfig new file mode 100644 index 000000000000..e566d89facaf --- /dev/null +++ b/packages/SettingsLib/IllustrationPreference/aconfig/illustrationpreference.aconfig @@ -0,0 +1,12 @@ +package: "com.android.settingslib.widget.flags" +container: "system" + +flag { + name: "auto_hide_empty_lottie_res" + namespace: "android_settings" + description: "Hides IllustrationPreference when Lottie resource is an empty file" + bug: "337873972" + metadata { + purpose: PURPOSE_BUGFIX + } +}
\ No newline at end of file diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java index 815a101957ad..bbf0315aa475 100644 --- a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java +++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/IllustrationPreference.java @@ -39,12 +39,14 @@ import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; import androidx.vectordrawable.graphics.drawable.Animatable2Compat; +import com.android.settingslib.widget.flags.Flags; import com.android.settingslib.widget.preference.illustration.R; import com.airbnb.lottie.LottieAnimationView; import com.airbnb.lottie.LottieDrawable; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; /** @@ -142,7 +144,7 @@ public class IllustrationPreference extends Preference { illustrationFrame.setLayoutParams(lp); illustrationView.setCacheComposition(mCacheComposition); - handleImageWithAnimation(illustrationView); + handleImageWithAnimation(illustrationView, illustrationFrame); handleImageFrameMaxHeight(backgroundView, illustrationView); if (mIsAutoScale) { @@ -332,7 +334,8 @@ public class IllustrationPreference extends Preference { } } - private void handleImageWithAnimation(LottieAnimationView illustrationView) { + private void handleImageWithAnimation(LottieAnimationView illustrationView, + ViewGroup container) { if (mImageDrawable != null) { resetAnimations(illustrationView); illustrationView.setImageDrawable(mImageDrawable); @@ -356,6 +359,25 @@ public class IllustrationPreference extends Preference { } if (mImageResId > 0) { + if (Flags.autoHideEmptyLottieRes()) { + // Check if resource is empty + try (InputStream is = illustrationView.getResources() + .openRawResource(mImageResId)) { + int check = is.read(); + // -1 = end of stream. if first read is end of stream, then file is empty + if (check == -1) { + illustrationView.setVisibility(View.GONE); + container.setVisibility(View.GONE); + return; + } + } catch (IOException e) { + Log.w(TAG, "Unable to open Lottie raw resource", e); + } + + illustrationView.setVisibility(View.VISIBLE); + container.setVisibility(View.VISIBLE); + } + resetAnimations(illustrationView); illustrationView.setImageResource(mImageResId); final Drawable drawable = illustrationView.getDrawable(); diff --git a/packages/SettingsLib/Spa/build.gradle.kts b/packages/SettingsLib/Spa/build.gradle.kts index 4147813bd059..e7823df7ce0e 100644 --- a/packages/SettingsLib/Spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/build.gradle.kts @@ -29,7 +29,7 @@ val androidTop: String = File(rootDir, "../../../../..").canonicalPath allprojects { extra["androidTop"] = androidTop - extra["jetpackComposeVersion"] = "1.7.0-alpha05" + extra["jetpackComposeVersion"] = "1.7.0-alpha08" } subprojects { diff --git a/packages/SettingsLib/Spa/spa/build.gradle.kts b/packages/SettingsLib/Spa/spa/build.gradle.kts index 6344501ce789..4aa57b3876fc 100644 --- a/packages/SettingsLib/Spa/spa/build.gradle.kts +++ b/packages/SettingsLib/Spa/spa/build.gradle.kts @@ -53,17 +53,17 @@ android { dependencies { api(project(":SettingsLibColor")) - api("androidx.appcompat:appcompat:1.7.0-alpha03") + api("androidx.appcompat:appcompat:1.7.0-beta01") api("androidx.slice:slice-builders:1.1.0-alpha02") api("androidx.slice:slice-core:1.1.0-alpha02") api("androidx.slice:slice-view:1.1.0-alpha02") - api("androidx.compose.material3:material3:1.3.0-alpha03") + api("androidx.compose.material3:material3:1.3.0-alpha06") api("androidx.compose.material:material-icons-extended:$jetpackComposeVersion") api("androidx.compose.runtime:runtime-livedata:$jetpackComposeVersion") api("androidx.compose.ui:ui-tooling-preview:$jetpackComposeVersion") api("androidx.lifecycle:lifecycle-livedata-ktx") api("androidx.lifecycle:lifecycle-runtime-compose") - api("androidx.navigation:navigation-compose:2.8.0-alpha05") + api("androidx.navigation:navigation-compose:2.8.0-alpha08") api("com.github.PhilJay:MPAndroidChart:v3.1.0-alpha") api("com.google.android.material:material:1.11.0") debugApi("androidx.compose.ui:ui-tooling:$jetpackComposeVersion") diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/AnnotatedStringResource.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/AnnotatedStringResource.kt index 88ba4b07d30a..1a10bf021f47 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/AnnotatedStringResource.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/AnnotatedStringResource.kt @@ -27,14 +27,13 @@ import androidx.compose.runtime.remember import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.LinkAnnotation import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDecoration -const val URL_SPAN_TAG = "URL_SPAN_TAG" - @Composable fun annotatedStringResource(@StringRes id: Int): AnnotatedString { val resources = LocalContext.current.resources @@ -97,12 +96,9 @@ private fun AnnotatedString.Builder.addUrlSpan( start: Int, end: Int, ) { - addStyle( - SpanStyle(color = urlSpanColor, textDecoration = TextDecoration.Underline), - start, - end, + val url = LinkAnnotation.Url( + url = urlSpan.url, + style = SpanStyle(color = urlSpanColor, textDecoration = TextDecoration.Underline), ) - if (!urlSpan.url.isNullOrEmpty()) { - addStringAnnotation(URL_SPAN_TAG, urlSpan.url, start, end) - } + addLink(url, start, end) } diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/AnnotatedText.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/AnnotatedText.kt index 82ac7e3bc9b2..f864fa970d0d 100644 --- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/AnnotatedText.kt +++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/AnnotatedText.kt @@ -17,26 +17,17 @@ package com.android.settingslib.spa.widget.ui import androidx.annotation.StringRes -import androidx.compose.foundation.text.ClickableText import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalUriHandler -import com.android.settingslib.spa.framework.util.URL_SPAN_TAG import com.android.settingslib.spa.framework.util.annotatedStringResource @Composable fun AnnotatedText(@StringRes id: Int) { - val uriHandler = LocalUriHandler.current - val annotatedString = annotatedStringResource(id) - ClickableText( - text = annotatedString, + Text( + text = annotatedStringResource(id), style = MaterialTheme.typography.bodyMedium.copy( color = MaterialTheme.colorScheme.onSurfaceVariant, ), - ) { offset -> - // Gets the url at the clicked position. - annotatedString.getStringAnnotations(URL_SPAN_TAG, offset, offset) - .firstOrNull() - ?.let { uriHandler.openUri(it.item) } - } + ) } diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/AnnotatedStringResourceTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/AnnotatedStringResourceTest.kt index 9928355ca089..612f9e525f20 100644 --- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/AnnotatedStringResourceTest.kt +++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/AnnotatedStringResourceTest.kt @@ -19,6 +19,7 @@ package com.android.settingslib.spa.framework.util import androidx.compose.material3.MaterialTheme import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.LinkAnnotation import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.font.FontWeight @@ -36,18 +37,23 @@ class AnnotatedStringResourceTest { val composeTestRule = createComposeRule() @Test - fun testAnnotatedStringResource() { + fun annotatedStringResource() { composeTestRule.setContent { val annotatedString = annotatedStringResource(R.string.test_annotated_string_resource) - val annotations = annotatedString.getStringAnnotations(0, annotatedString.length) + val annotations = annotatedString.getLinkAnnotations(0, annotatedString.length) assertThat(annotations).containsExactly( AnnotatedString.Range( - item = "https://www.android.com/", + item = LinkAnnotation.Url( + url = "https://www.android.com/", + style = SpanStyle( + color = MaterialTheme.colorScheme.primary, + textDecoration = TextDecoration.Underline, + ), + ), start = 31, end = 35, - tag = URL_SPAN_TAG, ) ) @@ -57,14 +63,6 @@ class AnnotatedStringResourceTest { start = 22, end = 26, ), - AnnotatedString.Range( - item = SpanStyle( - color = MaterialTheme.colorScheme.primary, - textDecoration = TextDecoration.Underline, - ), - start = 31, - end = 35, - ), ) } } diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig index 89f54d9b3b3b..9c0d29df420f 100644 --- a/packages/SettingsLib/aconfig/settingslib.aconfig +++ b/packages/SettingsLib/aconfig/settingslib.aconfig @@ -62,3 +62,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "allow_all_widgets_on_lockscreen_by_default" + namespace: "systemui" + description: "Allow all widgets on the lock screen by default." + bug: "328261690" +} diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 1594e8e75cb6..ad5337c3982f 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -105,9 +105,9 @@ <string name="bluetooth_battery_level_untethered_right" msgid="8377995536997790142">"Regs: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string> <string name="bluetooth_active_no_battery_level" msgid="4155462233006205630">"Aktief"</string> <string name="bluetooth_saved_device" msgid="4895871321722311428">"Gestoor"</string> - <string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktief (net linkerkant)"</string> - <string name="bluetooth_hearing_aid_right_active" msgid="2244728507170385397">"Aktief (net regterkant)"</string> - <string name="bluetooth_hearing_aid_left_and_right_active" msgid="4294571497939983181">"Aktief (linkerkant en regterkant)"</string> + <string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Aktief (net links)"</string> + <string name="bluetooth_hearing_aid_right_active" msgid="2244728507170385397">"Aktief (net regs)"</string> + <string name="bluetooth_hearing_aid_left_and_right_active" msgid="4294571497939983181">"Aktief (links en regs)"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Aktief (net media). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Aktiewe (net media). L: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, R: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> battery"</string> <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Gekoppel (steun oudiodeling). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> battery"</string> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 0cfae920c039..1a0fec5d431a 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -125,7 +125,7 @@ <string name="bluetooth_profile_opp" msgid="6692618568149493430">"Transferencia de archivos"</string> <string name="bluetooth_profile_hid" msgid="2969922922664315866">"Dispositivo de entrada"</string> <string name="bluetooth_profile_pan" msgid="1006235139308318188">"Acceso a Internet"</string> - <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Acceso a contactos e historial de llamadas"</string> + <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"Acceso a historial de llamadas y contactos"</string> <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"Se usará la información para anuncios de llamadas y más"</string> <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"Compartir conexión a Internet"</string> <string name="bluetooth_profile_map" msgid="8907204701162107271">"Mensajes de texto"</string> @@ -281,7 +281,7 @@ <string name="keep_screen_on_summary" msgid="1510731514101925829">"La pantalla nunca quedará inactiva mientras el dispositivo se esté cargando"</string> <string name="bt_hci_snoop_log" msgid="7291287955649081448">"Registro de Bluetooth HCI"</string> <string name="bt_hci_snoop_log_summary" msgid="6808538971394092284">"Capturar paquetes de Bluetooth (activa/desactiva el Bluetooth después de cambiar esta configuración)"</string> - <string name="oem_unlock_enable" msgid="5334869171871566731">"Desbloqueo de OEM"</string> + <string name="oem_unlock_enable" msgid="5334869171871566731">"Desbloqueo para OEM"</string> <string name="oem_unlock_enable_summary" msgid="5857388174390953829">"Permitir que el cargador de inicio se desbloquee"</string> <string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"¿Permitir desbloqueo de OEM?"</string> <string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"ADVERTENCIA: Las funciones de protección de dispositivos no funcionarán en este dispositivo mientras esta configuración esté activada."</string> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 497fbbb13a67..c330b7684fe5 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -294,7 +294,7 @@ <string name="wifi_scan_throttling" msgid="2985624788509913617">"Wifi-sareen bilaketaren moteltzea"</string> <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Wifi-konexioetan iraunkorrak ez diren MAC helbideak ausaz antolatzea"</string> <string name="mobile_data_always_on" msgid="8275958101875563572">"Datu-konexioa beti aktibo"</string> - <string name="tethering_hardware_offload" msgid="4116053719006939161">"Konexioa partekatzeko hardwarearen azelerazioa"</string> + <string name="tethering_hardware_offload" msgid="4116053719006939161">"Konexioa partekatzeko hardwarearen bizkortzea"</string> <string name="bluetooth_show_devices_without_names" msgid="923584526471885819">"Erakutsi Bluetooth bidezko gailuak izenik gabe"</string> <string name="bluetooth_disable_absolute_volume" msgid="1452342324349203434">"Desgaitu bolumen absolutua"</string> <string name="bluetooth_enable_gabeldorsche" msgid="9131730396242883416">"Gaitu Gabeldorsche"</string> @@ -339,7 +339,7 @@ <string name="allow_mock_location_summary" msgid="179780881081354579">"Onartu kokapen faltsuak"</string> <string name="debug_view_attributes" msgid="3539609843984208216">"Gaitu ikuspegiaren atributuak ikuskatzeko aukera"</string> <string name="mobile_data_always_on_summary" msgid="1112156365594371019">"Mantendu datu-konexioa beti aktibo, baita wifi-konexioa aktibo dagoenean ere (sare batetik bestera bizkor aldatu ahal izateko)."</string> - <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Erabilgarri badago, erabili konexioa partekatzeko hardwarearen azelerazioa"</string> + <string name="tethering_hardware_offload_summary" msgid="7801345335142803029">"Erabilgarri badago, erabili konexioa partekatzeko hardwarearen bizkortzea"</string> <string name="adb_warning_title" msgid="7708653449506485728">"USB bidezko arazketa onartu?"</string> <string name="adb_warning_message" msgid="8145270656419669221">"USB bidezko arazketa garapen-xedeetarako soilik dago diseinatuta. Erabil ezazu ordenagailuaren eta gailuaren artean datuak kopiatzeko, aplikazioak gailuan jakinarazi gabe instalatzeko eta erregistro-datuak irakurtzeko."</string> <string name="adbwifi_warning_title" msgid="727104571653031865">"Hari gabeko arazketa baimendu nahi duzu?"</string> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index 5e7f998a7e41..1d331fbf390c 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -96,8 +96,8 @@ <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"متصل (بدون تلفن یا رسانه)، باتری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"فعال. باتری: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_battery_level_untethered" msgid="4961338936672922617">"فعال. باتری چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، باتری راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> - <string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"فعال. باتری چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> - <string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"فعال. باتری راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> + <string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"فعال. چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> باتری."</string> + <string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"فعال. راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> باتری."</string> <string name="bluetooth_battery_level" msgid="2893696778200201555">"<xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> شارژ باتری"</string> <string name="tv_bluetooth_battery_level" msgid="8786353985605532846">"باتری <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_battery_level_untethered" msgid="1616774716076301755">"باتری چپ: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>، باتری راست: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g>."</string> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index e434d1efaabf..cfb6546057ca 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -126,7 +126,7 @@ <string name="bluetooth_profile_hid" msgid="2969922922664315866">"इनपुट डिवाइस"</string> <string name="bluetooth_profile_pan" msgid="1006235139308318188">"इंटरनेट का ऐक्सेस"</string> <string name="bluetooth_profile_pbap" msgid="2103406516858653017">"संपर्क और कॉल इतिहास का ऐक्सेस दें"</string> - <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"इस जानकारी का इस्तेमाल, कॉल की सूचना देने और दूसरी चीज़ों के लिए किया जाएगा"</string> + <string name="bluetooth_profile_pbap_summary" msgid="402819589201138227">"इस जानकारी का इस्तेमाल, कॉल की सूचना देने वगैरह के लिए किया जाएगा"</string> <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"इंटरनेट कनेक्शन साझाकरण"</string> <string name="bluetooth_profile_map" msgid="8907204701162107271">"लेख संदेश"</string> <string name="bluetooth_profile_sap" msgid="8304170950447934386">"सिम का ऐक्सेस"</string> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 4c0712c74ad1..5e3d779c34a2 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -159,7 +159,7 @@ <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Չեղարկել"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Զուգակցում է մուտքի թույլտվությունը դեպի ձեր կոնտակտները և զանգերի պատմությունը, երբ միացված է:"</string> <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Չհաջողվեց զուգակցել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string> - <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Չհաջողվեց զուգակցել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ սխալ PIN-ի կամ անցաբառի պատճառով:"</string> + <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Չհաջողվեց զուգակցել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ՝ սխալ PIN-ի կամ անցաբառի պատճառով:"</string> <string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Հնարավոր չէ կապ հաստատել <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string> <string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"Զուգավորումը մերժվեց <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի կողմից:"</string> <string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Համակարգիչ"</string> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index 4cd076b77fb9..be8d039ec07d 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -94,7 +94,7 @@ <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Поврзан со <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (без телефон), ниво на батеријата <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Поврзан со <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (без аудиовизуелни содржини), ниво на батеријата <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Поврзан со <xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g> (без телефон и аудиовизуелни содржини), ниво на батеријата <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> - <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Активно. <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија."</string> + <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Активно. Батерија: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> <string name="bluetooth_active_battery_level_untethered" msgid="4961338936672922617">"Активно. Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> батерија, Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батерија."</string> <string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"Активно. Л: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија."</string> <string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"Активно. Д: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батерија."</string> @@ -159,7 +159,7 @@ <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Откажи"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Кога е поврзано, спарувањето одобрува пристап до контактите и историјата на повиците."</string> <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Не може да се спари со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> - <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Не може да се спари со <xliff:g id="DEVICE_NAME">%1$s</xliff:g> поради погрешен PIN или лозинка."</string> + <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Не може да се спари со <xliff:g id="DEVICE_NAME">%1$s</xliff:g> поради погрешен PIN или криптографски клуч."</string> <string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Не може да комуницира со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> <string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"Спарувањето е одбиено од <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string> <string name="bluetooth_talkback_computer" msgid="3736623135703893773">"Компјутер"</string> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 42797d40ebaf..66efe8b3cf9a 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -94,7 +94,7 @@ <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Холбогдсон (утас байхгүй), батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Холбогдсон (медиа байхгүй), батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Холбогдсон (утас эсвэл медиа байхгүй), батарей <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> - <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Идэвхтэй байна. <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей."</string> + <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Идэвхтэй байна. <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> цэнэгтэй."</string> <string name="bluetooth_active_battery_level_untethered" msgid="4961338936672922617">"Идэвхтэй байна. З: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g>, Б: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> батарей."</string> <string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"Идэвхтэй байна. З: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей."</string> <string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"Идэвхтэй байна. Б: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> батарей."</string> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index 40d604e39954..8bafef3caf4f 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -157,7 +157,7 @@ <string name="bluetooth_pairing_accept" msgid="2054232610815498004">"कनेक्ट गर्नुहोस्"</string> <string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"जोडी"</string> <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"रद्द गर्नुहोस्"</string> - <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"जब जडान हुन्छ जोडी अनुदानले तपाईँको सम्पर्कहरू पहुँच गर्छ र इतिहास सम्झाउँछ।"</string> + <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"जब जडान हुन्छ जोडी अनुदानले तपाईँको कन्ट्याक्टहरू पहुँच गर्छ र इतिहास सम्झाउँछ।"</string> <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>सँग जोडा मिलाउन सकेन"</string> <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"गलत PIN वा पासकीका कारणले <xliff:g id="DEVICE_NAME">%1$s</xliff:g> मा कनेक्ट गर्न सकिएन।"</string> <string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> सँग कुराकानी हुन सक्दैन।"</string> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index 422d0f2c6256..d054d9b08d68 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -110,11 +110,11 @@ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="4294571497939983181">"Ativo (esquerdo e direito)"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Ativo (apenas mídia). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Ativo (apenas mídia). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> - <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Conectado (com suporte ao compartilhamento de áudio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> - <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Conectado (com suporte ao compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> - <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Conectado (com suporte ao compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> - <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Conectado (com suporte ao compartilhamento de áudio). Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> - <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Conectado (com suporte ao compartilhamento de áudio)"</string> + <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Conectado (aceita compartilhamento de áudio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> + <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Conectado (aceita compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> + <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Conectado (aceita compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> + <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Conectado (aceita compartilhamento de áudio). Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> + <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Conectado (aceita compartilhamento de áudio)"</string> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ativo (apenas mídia)"</string> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Com suporte ao compartilhamento de áudio"</string> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ativo (apenas mídia), apenas esquerdo"</string> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index 422d0f2c6256..d054d9b08d68 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -110,11 +110,11 @@ <string name="bluetooth_hearing_aid_left_and_right_active" msgid="4294571497939983181">"Ativo (esquerdo e direito)"</string> <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Ativo (apenas mídia). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Ativo (apenas mídia). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> - <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Conectado (com suporte ao compartilhamento de áudio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> - <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Conectado (com suporte ao compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> - <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Conectado (com suporte ao compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> - <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Conectado (com suporte ao compartilhamento de áudio). Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> - <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Conectado (com suporte ao compartilhamento de áudio)"</string> + <string name="bluetooth_battery_level_lea_support" msgid="5968584103507988820">"Conectado (aceita compartilhamento de áudio). <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> + <string name="bluetooth_battery_level_untethered_lea_support" msgid="803110681688633362">"Conectado (aceita compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> de bateria. Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> de bateria."</string> + <string name="bluetooth_battery_level_untethered_left_lea_support" msgid="7707464334346454950">"Conectado (aceita compartilhamento de áudio). Lado esquerdo: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> + <string name="bluetooth_battery_level_untethered_right_lea_support" msgid="8941549024377771038">"Conectado (aceita compartilhamento de áudio). Lado direito: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> de bateria."</string> + <string name="bluetooth_no_battery_level_lea_support" msgid="5721725041048434075">"Conectado (aceita compartilhamento de áudio)"</string> <string name="bluetooth_active_media_only_no_battery_level" msgid="71106861912593126">"Ativo (apenas mídia)"</string> <string name="bluetooth_saved_device_lea_support" msgid="7231323139968285768">"Com suporte ao compartilhamento de áudio"</string> <string name="bluetooth_hearing_aid_media_only_left_active" msgid="1632152540901488645">"Ativo (apenas mídia), apenas esquerdo"</string> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 54c9b0a71980..aaf648ea98a5 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -94,7 +94,7 @@ <string name="bluetooth_connected_no_headset_battery_level" msgid="2661863370509206428">"Подключено (кроме звонков), уровень заряда батареи: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_connected_no_a2dp_battery_level" msgid="6499078454894324287">"Подключено (кроме аудио), уровень заряда батареи: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> <string name="bluetooth_connected_no_headset_no_a2dp_battery_level" msgid="8477440576953067242">"Подключено (кроме звонков и аудио), уровень заряда батареи: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g><xliff:g id="ACTIVE_DEVICE">%2$s</xliff:g>"</string> - <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Используется, заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>."</string> + <string name="bluetooth_active_battery_level" msgid="2685517576209066008">"Используется, заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string> <string name="bluetooth_active_battery_level_untethered" msgid="4961338936672922617">"Используется, заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> (Л), <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> (П)."</string> <string name="bluetooth_active_battery_level_untethered_left" msgid="2895644748625343977">"Используется, заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (Л)"</string> <string name="bluetooth_active_battery_level_untethered_right" msgid="7407517998880370179">"Используется, заряд: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> (П)"</string> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index 4286c8144fb0..ed0b1dffd086 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -159,7 +159,7 @@ <string name="bluetooth_pairing_decline" msgid="6483118841204885890">"منسوخ کریں"</string> <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"منسلک ہونے پر جوڑا بنانے سے آپ کے رابطوں اور کال کی سرگزشت تک رسائی حاصل ہو جاتی ہے۔"</string> <string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> کے ساتھ جوڑا نہیں بنا سکا۔"</string> - <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"غلط PIN یا پاس کلید کی وجہ سے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کے ساتھ جوڑا نہیں بنا سکا۔"</string> + <string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"غلط PIN یا پاس کلید کی وجہ سے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کے ساتھ جوڑا نہیں بنایا جا سکا۔"</string> <string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> کے ساتھ مواصلت نہیں ہو سکتی۔"</string> <string name="bluetooth_pairing_rejected_error_message" msgid="5943444352777314442">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> نے جوڑا بنانے کو مسترد کر دیا۔"</string> <string name="bluetooth_talkback_computer" msgid="3736623135703893773">"کمپیوٹر"</string> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index 56282ec6fed1..25ca0c214d69 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -706,9 +706,9 @@ <string name="physical_keyboard_title" msgid="4811935435315835220">"实体键盘"</string> <string name="keyboard_layout_dialog_title" msgid="3927180147005616290">"选择键盘布局"</string> <string name="keyboard_layout_default_label" msgid="1997292217218546957">"默认"</string> - <string name="turn_screen_on_title" msgid="3266937298097573424">"开启屏幕"</string> + <string name="turn_screen_on_title" msgid="3266937298097573424">"唤醒屏幕"</string> <string name="allow_turn_screen_on" msgid="6194845766392742639">"允许开启屏幕"</string> - <string name="allow_turn_screen_on_description" msgid="43834403291575164">"允许应用开启屏幕。如获授权,该应用便可在您未明确表达意愿的情况下随时开启屏幕。"</string> + <string name="allow_turn_screen_on_description" msgid="43834403291575164">"允许应用唤醒屏幕。如获授权,该应用便可在您未明确表达意愿的情况下随时唤醒屏幕。"</string> <string name="bt_le_audio_broadcast_dialog_title" msgid="5392738488989777074">"要停止广播“<xliff:g id="APP_NAME">%1$s</xliff:g>”的内容吗?"</string> <string name="bt_le_audio_broadcast_dialog_sub_title" msgid="268234802198852753">"如果广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容或更改输出来源,当前的广播就会停止"</string> <string name="bt_le_audio_broadcast_dialog_switch_app" msgid="5749813313369517812">"广播“<xliff:g id="SWITCHAPP">%1$s</xliff:g>”的内容"</string> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index adbfc72cd684..4ea746007f76 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1712,7 +1712,7 @@ <string name="keyboard_layout_default_label">Default</string> <!-- Special access > Title for managing turn screen on settings. [CHAR LIMIT=50] --> - <string name="turn_screen_on_title">Turn screen on</string> + <string name="turn_screen_on_title">Screen turn-on control</string> <!-- Label for a setting which controls whether an app can turn the screen on [CHAR LIMIT=45] --> <string name="allow_turn_screen_on">Allow turning the screen on</string> <!-- Description for a setting which controls whether an app can turn the screen on [CHAR LIMIT=NONE] --> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 30bec7724dd5..c2a83b1e772f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -68,6 +68,7 @@ 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.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -1442,14 +1443,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> int stringRes = R.string.bluetooth_pairing; //when profile is connected, information would be available if (profileConnected) { - // Update Meta data for connected device - if (BluetoothUtils.getBooleanMetaData( - mDevice, BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) { - leftBattery = BluetoothUtils.getIntMetaData(mDevice, - BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY); - rightBattery = BluetoothUtils.getIntMetaData(mDevice, - BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY); - } + leftBattery = getLeftBatteryLevel(); + rightBattery = getRightBatteryLevel(); // Set default string with battery level in device connected situation. if (isTwsBatteryAvailable(leftBattery, rightBattery)) { @@ -1485,7 +1480,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> boolean isActiveLeAudioHearingAid = mIsActiveDeviceLeAudio && isConnectedHapClientDevice(); if (isActiveAshaHearingAid || isActiveLeAudioHearingAid) { - return getHearingDeviceSummary(leftBattery, rightBattery, shortSummary); + stringRes = getHearingDeviceSummaryRes(leftBattery, rightBattery, shortSummary); } } } @@ -1498,6 +1493,8 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> boolean summaryIncludesBatteryLevel = stringRes == R.string.bluetooth_battery_level || stringRes == R.string.bluetooth_active_battery_level || stringRes == R.string.bluetooth_active_battery_level_untethered + || stringRes == R.string.bluetooth_active_battery_level_untethered_left + || stringRes == R.string.bluetooth_active_battery_level_untethered_right || stringRes == R.string.bluetooth_battery_level_untethered; if (isTvSummary && summaryIncludesBatteryLevel && Flags.enableTvMediaOutputDialog()) { return getTvBatterySummary( @@ -1510,6 +1507,14 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> if (isTwsBatteryAvailable(leftBattery, rightBattery)) { return mContext.getString(stringRes, Utils.formatPercentage(leftBattery), Utils.formatPercentage(rightBattery)); + } else if (leftBattery > BluetoothDevice.BATTERY_LEVEL_UNKNOWN + && !BluetoothUtils.getBooleanMetaData(mDevice, + BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) { + return mContext.getString(stringRes, Utils.formatPercentage(leftBattery)); + } else if (rightBattery > BluetoothDevice.BATTERY_LEVEL_UNKNOWN + && !BluetoothUtils.getBooleanMetaData(mDevice, + BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) { + return mContext.getString(stringRes, Utils.formatPercentage(rightBattery)); } else { return mContext.getString(stringRes, batteryLevelPercentageString); } @@ -1553,60 +1558,34 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return spannableBuilder; } - private CharSequence getHearingDeviceSummary(int leftBattery, int rightBattery, + private int getHearingDeviceSummaryRes(int leftBattery, int rightBattery, boolean shortSummary) { + boolean isLeftDeviceConnected = getConnectedHearingAidSide( + HearingAidInfo.DeviceSide.SIDE_LEFT).isPresent(); + boolean isRightDeviceConnected = getConnectedHearingAidSide( + HearingAidInfo.DeviceSide.SIDE_RIGHT).isPresent(); + boolean shouldShowLeftBattery = + !shortSummary && (leftBattery > BluetoothDevice.BATTERY_LEVEL_UNKNOWN); + boolean shouldShowRightBattery = + !shortSummary && (rightBattery > BluetoothDevice.BATTERY_LEVEL_UNKNOWN); - CachedBluetoothDevice memberDevice = getMemberDevice().stream().filter( - CachedBluetoothDevice::isConnected).findFirst().orElse(null); - if (memberDevice == null && mSubDevice != null && mSubDevice.isConnected()) { - memberDevice = mSubDevice; - } - - CachedBluetoothDevice leftDevice = null; - CachedBluetoothDevice rightDevice = null; - final int deviceSide = getDeviceSide(); - if (deviceSide == HearingAidInfo.DeviceSide.SIDE_LEFT) { - leftDevice = this; - rightDevice = memberDevice; - } else if (deviceSide == HearingAidInfo.DeviceSide.SIDE_RIGHT) { - leftDevice = memberDevice; - rightDevice = this; - } else if (deviceSide == HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT) { - leftDevice = this; - rightDevice = this; + if (isLeftDeviceConnected && isRightDeviceConnected) { + return (shouldShowLeftBattery && shouldShowRightBattery) + ? R.string.bluetooth_active_battery_level_untethered + : R.string.bluetooth_hearing_aid_left_and_right_active; } - - if (leftBattery < 0 && leftDevice != null) { - leftBattery = leftDevice.getBatteryLevel(); + if (isLeftDeviceConnected) { + return shouldShowLeftBattery + ? R.string.bluetooth_active_battery_level_untethered_left + : R.string.bluetooth_hearing_aid_left_active; } - if (rightBattery < 0 && rightDevice != null) { - rightBattery = rightDevice.getBatteryLevel(); - } - - if (leftDevice != null && rightDevice != null) { - if (leftBattery >= 0 && rightBattery >= 0 && !shortSummary) { - return mContext.getString(R.string.bluetooth_active_battery_level_untethered, - Utils.formatPercentage(leftBattery), Utils.formatPercentage(rightBattery)); - } else { - return mContext.getString(R.string.bluetooth_hearing_aid_left_and_right_active); - } - } else if (leftDevice != null) { - if (leftBattery >= 0 && !shortSummary) { - return mContext.getString(R.string.bluetooth_active_battery_level_untethered_left, - Utils.formatPercentage(leftBattery)); - } else { - return mContext.getString(R.string.bluetooth_hearing_aid_left_active); - } - } else if (rightDevice != null) { - if (rightBattery >= 0 && !shortSummary) { - return mContext.getString(R.string.bluetooth_active_battery_level_untethered_right, - Utils.formatPercentage(rightBattery)); - } else { - return mContext.getString(R.string.bluetooth_hearing_aid_right_active); - } + if (isRightDeviceConnected) { + return shouldShowRightBattery + ? R.string.bluetooth_active_battery_level_untethered_right + : R.string.bluetooth_hearing_aid_right_active; } - return mContext.getString(R.string.bluetooth_active_no_battery_level); + return R.string.bluetooth_active_no_battery_level; } private void addBatterySpan(SpannableStringBuilder builder, @@ -1632,6 +1611,56 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return leftBattery >= 0 && rightBattery >= 0; } + private Optional<CachedBluetoothDevice> getConnectedHearingAidSide( + @HearingAidInfo.DeviceSide int side) { + return Stream.concat(Stream.of(this, mSubDevice), mMemberDevices.stream()) + .filter(Objects::nonNull) + .filter(device -> device.getDeviceSide() == side + || device.getDeviceSide() == HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT) + .filter(device -> device.getDevice().isConnected()) + // For hearing aids, we should expect only one device assign to one side, but if + // it happens, we don't care which one. + .findAny(); + } + + private int getLeftBatteryLevel() { + int leftBattery = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + if (BluetoothUtils.getBooleanMetaData(mDevice, + BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) { + leftBattery = BluetoothUtils.getIntMetaData(mDevice, + BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY); + } + + // Retrieve hearing aids (ASHA, HAP) individual side battery level + if (leftBattery == BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { + leftBattery = getConnectedHearingAidSide(HearingAidInfo.DeviceSide.SIDE_LEFT) + .map(CachedBluetoothDevice::getBatteryLevel) + .filter(batteryLevel -> batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN) + .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN); + } + + return leftBattery; + } + + private int getRightBatteryLevel() { + int rightBattery = BluetoothDevice.BATTERY_LEVEL_UNKNOWN; + if (BluetoothUtils.getBooleanMetaData( + mDevice, BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) { + rightBattery = BluetoothUtils.getIntMetaData(mDevice, + BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY); + } + + // Retrieve hearing aids (ASHA, HAP) individual side battery level + if (rightBattery == BluetoothDevice.BATTERY_LEVEL_UNKNOWN) { + rightBattery = getConnectedHearingAidSide(HearingAidInfo.DeviceSide.SIDE_RIGHT) + .map(CachedBluetoothDevice::getBatteryLevel) + .filter(batteryLevel -> batteryLevel > BluetoothDevice.BATTERY_LEVEL_UNKNOWN) + .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN); + } + + return rightBattery; + } + private boolean isProfileConnectedFail() { Log.d(TAG, "anonymizedAddress=" + mDevice.getAnonymizedAddress() + " mIsA2dpProfileConnectedFail=" + mIsA2dpProfileConnectedFail diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java index 822a60889931..1040ac6bc860 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java @@ -36,6 +36,7 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import androidx.annotation.GuardedBy; import androidx.annotation.VisibleForTesting; import com.android.internal.telephony.SmsApplication; @@ -56,13 +57,22 @@ public class PowerAllowlistBackend { private static PowerAllowlistBackend sInstance; + private final Object mAllowlistedAppsLock = new Object(); + private final Object mSysAllowlistedAppsLock = new Object(); + private final Object mDefaultActiveAppsLock = new Object(); + private final Context mAppContext; private final IDeviceIdleController mDeviceIdleService; + + @GuardedBy("mAllowlistedAppsLock") private final ArraySet<String> mAllowlistedApps = new ArraySet<>(); + @GuardedBy("mSysAllowlistedAppsLock") private final ArraySet<String> mSysAllowlistedApps = new ArraySet<>(); + @GuardedBy("mDefaultActiveAppsLock") private final ArraySet<String> mDefaultActiveApps = new ArraySet<>(); - public PowerAllowlistBackend(Context context) { + @VisibleForTesting + PowerAllowlistBackend(Context context) { this(context, IDeviceIdleController.Stub.asInterface( ServiceManager.getService(DEVICE_IDLE_SERVICE))); } @@ -75,24 +85,25 @@ public class PowerAllowlistBackend { } public int getAllowlistSize() { - return mAllowlistedApps.size(); + synchronized (mAllowlistedAppsLock) { + return mAllowlistedApps.size(); + } } - /** - * Check if target package is in System allow list - */ + /** Check if target package is in System allow list */ public boolean isSysAllowlisted(String pkg) { - return mSysAllowlistedApps.contains(pkg); + synchronized (mSysAllowlistedAppsLock) { + return mSysAllowlistedApps.contains(pkg); + } } - /** - * Check if target package is in allow list - */ + /** Check if target package is in allow list */ public boolean isAllowlisted(String pkg, int uid) { - if (mAllowlistedApps.contains(pkg)) { - return true; + synchronized (mAllowlistedAppsLock) { + if (mAllowlistedApps.contains(pkg)) { + return true; + } } - if (isDefaultActiveApp(pkg, uid)) { return true; } @@ -100,16 +111,16 @@ public class PowerAllowlistBackend { return false; } - /** - * Check if it is default active app in multiple area(i.e. SMS, Dialer, Device admin..) - */ + /** Check if it is default active app in multiple area */ public boolean isDefaultActiveApp(String pkg, int uid) { // Additionally, check if pkg is default dialer/sms. They are considered essential apps and // should be automatically allowlisted (otherwise user may be able to set restriction on // them, leading to bad device behavior.) - if (mDefaultActiveApps.contains(pkg)) { - return true; + synchronized (mDefaultActiveAppsLock) { + if (mDefaultActiveApps.contains(pkg)) { + return true; + } } final DevicePolicyManager devicePolicyManager = mAppContext.getSystemService( @@ -143,9 +154,7 @@ public class PowerAllowlistBackend { DEFAULT_SYSTEM_EXEMPT_POWER_RESTRICTIONS_ENABLED); } - /** - * Check if target package is in allow list except idle app - */ + /** Check if target package is in allow list except idle app */ public boolean isAllowlistedExceptIdle(String pkg) { try { return mDeviceIdleService.isPowerSaveWhitelistExceptIdleApp(pkg); @@ -156,6 +165,7 @@ public class PowerAllowlistBackend { } /** + * Check if target package is in allow list except idle app * * @param pkgs a list of packageName * @return true when one of package is in allow list @@ -174,20 +184,21 @@ public class PowerAllowlistBackend { } /** - * Add app into power save allow list. + * Add app into power save allow list + * * @param pkg packageName of the app */ - // TODO: Fix all callers to pass in UID public void addApp(String pkg) { addApp(pkg, Process.INVALID_UID); } /** - * Add app into power save allow list. + * Add app into power save allow list + * * @param pkg packageName of the app * @param uid uid of the app */ - public void addApp(String pkg, int uid) { + public synchronized void addApp(String pkg, int uid) { try { if (android.app.Flags.appRestrictionsApi()) { if (uid == Process.INVALID_UID) { @@ -204,7 +215,9 @@ public class PowerAllowlistBackend { } mDeviceIdleService.addPowerSaveWhitelistApp(pkg); - mAllowlistedApps.add(pkg); + synchronized (mAllowlistedAppsLock) { + mAllowlistedApps.add(pkg); + } } catch (RemoteException e) { Log.w(TAG, "Unable to reach IDeviceIdleController", e); } catch (NameNotFoundException e) { @@ -213,7 +226,8 @@ public class PowerAllowlistBackend { } /** - * Remove package from power save allow list. + * Remove package from power save allow list + * * @param pkg packageName of the app */ public void removeApp(String pkg) { @@ -222,10 +236,11 @@ public class PowerAllowlistBackend { /** * Remove package from power save allow list. + * * @param pkg packageName of the app * @param uid uid of the app */ - public void removeApp(String pkg, int uid) { + public synchronized void removeApp(String pkg, int uid) { try { if (android.app.Flags.appRestrictionsApi()) { if (uid == Process.INVALID_UID) { @@ -241,7 +256,9 @@ public class PowerAllowlistBackend { } mDeviceIdleService.removePowerSaveWhitelistApp(pkg); - mAllowlistedApps.remove(pkg); + synchronized (mAllowlistedAppsLock) { + mAllowlistedApps.remove(pkg); + } } catch (RemoteException e) { Log.w(TAG, "Unable to reach IDeviceIdleController", e); } catch (NameNotFoundException e) { @@ -249,25 +266,33 @@ public class PowerAllowlistBackend { } } - /** - * Refresh all of lists - */ + /** Refresh all of lists */ @VisibleForTesting - public void refreshList() { - mSysAllowlistedApps.clear(); - mAllowlistedApps.clear(); - mDefaultActiveApps.clear(); + public synchronized void refreshList() { + synchronized (mSysAllowlistedAppsLock) { + mSysAllowlistedApps.clear(); + } + synchronized (mAllowlistedAppsLock) { + mAllowlistedApps.clear(); + } + synchronized (mDefaultActiveAppsLock) { + mDefaultActiveApps.clear(); + } if (mDeviceIdleService == null) { return; } try { final String[] allowlistedApps = mDeviceIdleService.getFullPowerWhitelist(); - for (String app : allowlistedApps) { - mAllowlistedApps.add(app); + synchronized (mAllowlistedAppsLock) { + for (String app : allowlistedApps) { + mAllowlistedApps.add(app); + } } final String[] sysAllowlistedApps = mDeviceIdleService.getSystemPowerWhitelist(); - for (String app : sysAllowlistedApps) { - mSysAllowlistedApps.add(app); + synchronized (mSysAllowlistedAppsLock) { + for (String app : sysAllowlistedApps) { + mSysAllowlistedApps.add(app); + } } final boolean hasTelephony = mAppContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY); @@ -278,26 +303,28 @@ public class PowerAllowlistBackend { if (hasTelephony) { if (defaultSms != null) { - mDefaultActiveApps.add(defaultSms.getPackageName()); + synchronized (mDefaultActiveAppsLock) { + mDefaultActiveApps.add(defaultSms.getPackageName()); + } } if (!TextUtils.isEmpty(defaultDialer)) { - mDefaultActiveApps.add(defaultDialer); + synchronized (mDefaultActiveAppsLock) { + mDefaultActiveApps.add(defaultDialer); + } } } - } catch (RemoteException e) { - Log.w(TAG, "Unable to reach IDeviceIdleController", e); + } catch (Exception e) { + Log.e(TAG, "Failed to invoke refreshList()", e); } } - /** - * @param context - * @return a PowerAllowlistBackend object - */ + /** Get the {@link PowerAllowlistBackend} instance */ public static PowerAllowlistBackend getInstance(Context context) { - if (sInstance == null) { - sInstance = new PowerAllowlistBackend(context); + synchronized (PowerAllowlistBackend.class) { + if (sInstance == null) { + sInstance = new PowerAllowlistBackend(context); + } + return sInstance; } - return sInstance; } - } diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp index f4ddd0ac59df..f87b5190c7a1 100644 --- a/packages/SettingsLib/tests/robotests/Android.bp +++ b/packages/SettingsLib/tests/robotests/Android.bp @@ -51,6 +51,7 @@ android_robolectric_test { "androidx.core_core", "flag-junit", "settingslib_media_flags_lib", + "settingslib_illustrationpreference_flags_lib", "testng", // TODO: remove once JUnit on Android provides assertThrows ], java_resource_dirs: ["config"], diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java index b4bd4826ea08..b9bf9caddac7 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java @@ -753,33 +753,71 @@ public class CachedBluetoothDeviceTest { } @Test - public void getConnectionSummary_testHearingAidBatteryWithoutInCall_returnActiveBattery() { + public void getConnectionSummary_testHearingAidLeftEarBatteryNotInCall_returnActiveBattery() { // Arrange: - // 1. Profile: {HEARING_AID, Connected, Active} + // 1. Profile: {HEARING_AID, Connected, Active, Left ear} // 2. Battery Level: 10 // 3. Audio Manager: Normal (Without In Call) updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); mBatteryLevel = 10; // Act & Assert: - // Get "Active, 10% battery" result with Battery Level 10. - assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 10% battery"); + // Get "Active. L: 10% battery." result with Battery Level 10. + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active. L: 10% battery."); } @Test - public void getTvConnectionSummary_testHearingAidBatteryWithoutInCall_returnBattery() { + public void getTvConnectionSummary_testHearingAidLeftEarBatteryWithoutInCall_returnBattery() { // Arrange: - // 1. Profile: {HEARING_AID, Connected, Active} + // 1. Profile: {HEARING_AID, Connected, Active, Left ear} // 2. Battery Level: 10 // 3. Audio Manager: Normal (Without In Call) updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); mBatteryLevel = 10; // Act & Assert: - // Get "Active, 10% battery" result with Battery Level 10. - assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + // Get "Left: 10% battery" result with Battery Level 10. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Left: 10% battery"); + } + + @Test + public void getConnectionSummary_testHearingAidLeftEarBatteryInCall_returnActiveBattery() { + // Arrange: + // 1. Profile: {HEARING_AID, Connected, Active, Left ear} + // 2. Battery Level: 10 + // 3. Audio Manager: In Call + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + mAudioManager.setMode(AudioManager.MODE_IN_CALL); + mBatteryLevel = 10; + + // Act & Assert: + // Get "Active. L: 10% battery." result with Battery Level 10. + assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active. L: 10% battery."); + } + + @Test + public void getTvConnectionSummary_testHearingAidLeftEarBatteryInCall_returnBattery() { + // Arrange: + // 1. Profile: {HEARING_AID, Connected, Active, Left ear} + // 2. Battery Level: 10 + // 3. Audio Manager: In Call + updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + mAudioManager.setMode(AudioManager.MODE_IN_CALL); + mBatteryLevel = 10; + + // Act & Assert: + // Get "Left: 10% battery" result with Battery Level 10. + assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( + "Left: 10% battery"); } @Test @@ -851,35 +889,45 @@ public class CachedBluetoothDeviceTest { } @Test - public void getConnectionSummary_testHearingAidBatteryInCall_returnActiveBattery() { + public void getConnectionSummary_testHearingAidBothEarBattery_returnActiveBattery() { // Arrange: - // 1. Profile: {HEARING_AID, Connected, Active} + // 1. Profile: {HEARING_AID, Connected, Active, Both ear} // 2. Battery Level: 10 // 3. Audio Manager: In Call + mCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo()); updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mSubCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); + updateSubDeviceProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setSubDevice(mSubCachedDevice); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); mAudioManager.setMode(AudioManager.MODE_IN_CALL); mBatteryLevel = 10; // Act & Assert: - // Get "Active, 10% battery" result with Battery Level 10. - assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, 10% battery"); + // Get "Active. L: 10%, R: 10% battery." result with Battery Level 10. + assertThat(mCachedDevice.getConnectionSummary().toString()) + .isEqualTo("Active. L: 10%, R: 10% battery."); } @Test - public void getTvConnectionSummary_testHearingAidBatteryInCall_returnBattery() { + public void getTvConnectionSummary_testHearingAidBothEarBattery_returnActiveBattery() { // Arrange: - // 1. Profile: {HEARING_AID, Connected, Active} + // 1. Profile: {HEARING_AID, Connected, Active, Both ear} // 2. Battery Level: 10 // 3. Audio Manager: In Call + mCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo()); updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mSubCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo()); + updateSubDeviceProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); + mCachedDevice.setSubDevice(mSubCachedDevice); mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); mAudioManager.setMode(AudioManager.MODE_IN_CALL); mBatteryLevel = 10; // Act & Assert: - // Get "Active, 10% battery" result with Battery Level 10. - assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo("Battery 10%"); + // Get "Left: 10% battery Right: 10% battery" result with Battery Level 10. + assertThat(mCachedDevice.getTvConnectionSummary().toString()) + .isEqualTo("Left: 10% battery Right: 10% battery"); } @Test @@ -1151,7 +1199,7 @@ public class CachedBluetoothDeviceTest { updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); - mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( "true".getBytes()); when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn( @@ -1160,7 +1208,7 @@ public class CachedBluetoothDeviceTest { TWS_BATTERY_RIGHT.getBytes()); assertThat(mCachedDevice.getConnectionSummary()).isEqualTo( - "Active, L: 15% battery, R: 25% battery"); + "Active. L: 15%, R: 25% battery."); } @Test @@ -1169,7 +1217,7 @@ public class CachedBluetoothDeviceTest { updateProfileStatus(mHfpProfile, BluetoothProfile.STATE_CONNECTED); updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED); when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED); - mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID); + mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.A2DP); when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn( "true".getBytes()); when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn( @@ -1178,7 +1226,7 @@ public class CachedBluetoothDeviceTest { TWS_BATTERY_RIGHT.getBytes()); assertThat(mCachedDevice.getTvConnectionSummary().toString()).isEqualTo( - "Left 15% Right 25%"); + "Left: 15% battery Right: 25% battery"); } @Test @@ -1741,16 +1789,6 @@ public class CachedBluetoothDeviceTest { BluetoothProfile.STATE_CONNECTED); } - private void updateProfileStatus(LocalBluetoothProfile profile, int status) { - doReturn(status).when(profile).getConnectionStatus(mDevice); - mCachedDevice.onProfileStateChanged(profile, status); - } - - private void updateSubDeviceProfileStatus(LocalBluetoothProfile profile, int status) { - doReturn(status).when(profile).getConnectionStatus(mSubDevice); - mSubCachedDevice.onProfileStateChanged(profile, status); - } - @Test public void getSubDevice_setSubDevice() { mCachedDevice.setSubDevice(mSubCachedDevice); @@ -2030,6 +2068,29 @@ public class CachedBluetoothDeviceTest { assertThat(mCachedDevice.getConnectionSummary(false)).isNull(); } + private void updateProfileStatus(LocalBluetoothProfile profile, int status) { + doReturn(status).when(profile).getConnectionStatus(mDevice); + mCachedDevice.onProfileStateChanged(profile, status); + updateConnectionStatus(mCachedDevice); + } + + private void updateSubDeviceProfileStatus(LocalBluetoothProfile profile, int status) { + doReturn(status).when(profile).getConnectionStatus(mSubDevice); + mSubCachedDevice.onProfileStateChanged(profile, status); + updateConnectionStatus(mSubCachedDevice); + } + + private void updateConnectionStatus(CachedBluetoothDevice cachedBluetoothDevice) { + for (LocalBluetoothProfile profile : cachedBluetoothDevice.getProfiles()) { + int status = cachedBluetoothDevice.getProfileConnectionState(profile); + if (status == BluetoothProfile.STATE_CONNECTED) { + when(cachedBluetoothDevice.getDevice().isConnected()).thenReturn(true); + return; + } + } + when(cachedBluetoothDevice.getDevice().isConnected()).thenReturn(false); + } + private HearingAidInfo getLeftAshaHearingAidInfo() { return new HearingAidInfo.Builder() .setAshaDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT) diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java index 6590bbdcdae6..ca53fc2ba47e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/IllustrationPreferenceTest.java @@ -26,10 +26,14 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import android.content.Context; +import android.content.res.Resources; import android.graphics.drawable.AnimatedImageDrawable; import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.AnimationDrawable; import android.net.Uri; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; @@ -39,11 +43,13 @@ import android.widget.ImageView; import androidx.preference.PreferenceViewHolder; import androidx.test.core.app.ApplicationProvider; +import com.android.settingslib.widget.flags.Flags; import com.android.settingslib.widget.preference.illustration.R; import com.airbnb.lottie.LottieAnimationView; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -51,10 +57,14 @@ import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; +import java.io.ByteArrayInputStream; + @RunWith(RobolectricTestRunner.class) public class IllustrationPreferenceTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Mock private ViewGroup mRootView; private Uri mImageUri; @@ -66,6 +76,7 @@ public class IllustrationPreferenceTest { private final Context mContext = ApplicationProvider.getApplicationContext(); private IllustrationPreference.OnBindListener mOnBindListener; private LottieAnimationView mOnBindListenerAnimationView; + private FrameLayout mIllustrationFrame; @Before public void setUp() { @@ -75,14 +86,14 @@ public class IllustrationPreferenceTest { mBackgroundView = new ImageView(mContext); mAnimationView = spy(new LottieAnimationView(mContext)); mMiddleGroundLayout = new FrameLayout(mContext); - final FrameLayout illustrationFrame = new FrameLayout(mContext); - illustrationFrame.setLayoutParams( + mIllustrationFrame = new FrameLayout(mContext); + mIllustrationFrame.setLayoutParams( new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); doReturn(mMiddleGroundLayout).when(mRootView).findViewById(R.id.middleground_layout); doReturn(mBackgroundView).when(mRootView).findViewById(R.id.background_view); doReturn(mAnimationView).when(mRootView).findViewById(R.id.lottie_view); - doReturn(illustrationFrame).when(mRootView).findViewById(R.id.illustration_frame); + doReturn(mIllustrationFrame).when(mRootView).findViewById(R.id.illustration_frame); mViewHolder = spy(PreferenceViewHolder.createInstanceForTests(mRootView)); final AttributeSet attributeSet = Robolectric.buildAttributeSet().build(); @@ -158,11 +169,13 @@ public class IllustrationPreferenceTest { } @Test + @DisableFlags(Flags.FLAG_AUTO_HIDE_EMPTY_LOTTIE_RES) public void playLottieAnimationWithResource_verifyFailureListener() { // fake the valid lottie image final int fakeValidResId = 111; doNothing().when(mAnimationView).setImageResource(fakeValidResId); doReturn(null).when(mAnimationView).getDrawable(); + doNothing().when(mAnimationView).setAnimation(fakeValidResId); mPreference.setLottieAnimationResId(fakeValidResId); mPreference.onBindViewHolder(mViewHolder); @@ -171,6 +184,50 @@ public class IllustrationPreferenceTest { } @Test + @DisableFlags(Flags.FLAG_AUTO_HIDE_EMPTY_LOTTIE_RES) + public void handleImageWithAnimation_emptyInputStreamDisabledFlag_verifyContainerVisible() { + doNothing().when(mAnimationView).setImageResource(111); + doReturn(null).when(mAnimationView).getDrawable(); + + mPreference.setLottieAnimationResId(111); + mPreference.onBindViewHolder(mViewHolder); + + assertThat(mAnimationView.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mIllustrationFrame.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + @EnableFlags(Flags.FLAG_AUTO_HIDE_EMPTY_LOTTIE_RES) + public void handleImageWithAnimation_emptyInputStreamEnabledFlag_verifyContainerHidden() { + Resources res = spy(mContext.getResources()); + doReturn(res).when(mAnimationView).getResources(); + doReturn(new ByteArrayInputStream(new byte[] {})).when(res).openRawResource(111); + + mPreference.setLottieAnimationResId(111); + mPreference.onBindViewHolder(mViewHolder); + + assertThat(mAnimationView.getVisibility()).isEqualTo(View.GONE); + assertThat(mIllustrationFrame.getVisibility()).isEqualTo(View.GONE); + } + + @Test + @EnableFlags(Flags.FLAG_AUTO_HIDE_EMPTY_LOTTIE_RES) + public void handleImageWithAnimation_nonEmptyInputStreamEnabledFlag_verifyContainerVisible() { + Resources res = spy(mContext.getResources()); + doReturn(res).when(mAnimationView).getResources(); + doReturn(new ByteArrayInputStream(new byte[] { 1, 2, 3 })).when(res).openRawResource(111); + doNothing().when(mAnimationView).setImageResource(111); + doNothing().when(mAnimationView).setAnimation(111); + doReturn(null).when(mAnimationView).getDrawable(); + + mPreference.setLottieAnimationResId(111); + mPreference.onBindViewHolder(mViewHolder); + + assertThat(mAnimationView.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mIllustrationFrame.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test public void setMaxHeight_smallerThanRestrictedHeight_matchResult() { final int restrictedHeight = mContext.getResources().getDimensionPixelSize( diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index fce7a00f9744..c04ec4f61c89 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -569,7 +569,7 @@ android_library { "androidx.test.uiautomator_uiautomator", "androidx.core_core-animation-testing", "mockito-target-extended-minus-junit4", - "mockito-kotlin2", + "mockito-kotlin-nodeps", "androidx.test.ext.junit", "androidx.test.ext.truth", "kotlin-test", @@ -656,6 +656,7 @@ java_library { "androidx.core_core-animation-testing", "androidx.test.ext.junit", "inline-mockito-robolectric-prebuilt", + "mockito-kotlin-nodeps", "platform-parametric-runner-lib", "SystemUICustomizationTestUtils", "kotlin-test", @@ -740,6 +741,7 @@ android_ravenwood_test { "androidx.core_core-animation-testing", "androidx.test.ext.junit", "kosmos", + "mockito-kotlin-nodeps", ], libs: [ "android.test.runner", diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index e69ac0a555b6..582b6a1489f7 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -470,6 +470,17 @@ flag { } flag { + name: "fix_screenshot_action_dismiss_system_windows" + namespace: "systemui" + description: "Dismiss existing system windows when starting action from screenshot UI" + bug: "309933761" + metadata { + purpose: PURPOSE_BUGFIX + } +} + + +flag { name: "screenshot_private_profile_behavior_fix" namespace: "systemui" description: "Private profile support for screenshots" @@ -882,3 +893,23 @@ flag { description: "Enables Backlinks improvement feature in App Clips" bug: "300307759" } + +flag { + name: "qs_custom_tile_click_guaranteed_bug_fix" + namespace: "systemui" + description: "Guarantee that clicks on a tile always happen by postponing onStopListening until after the click." + bug: "339290820" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "media_controls_user_initiated_dismiss" + namespace: "systemui" + description: "Only dismiss media notifications when the control was removed by the user." + bug: "335875159" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt index d4660fa74f0a..23df26fdb246 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt @@ -23,6 +23,7 @@ import android.app.TaskInfo import android.graphics.Matrix import android.graphics.Rect import android.graphics.RectF +import android.os.Binder import android.os.Build import android.os.Handler import android.os.Looper @@ -36,7 +37,11 @@ import android.view.SyncRtSurfaceTransactionApplier import android.view.View import android.view.ViewGroup import android.view.WindowManager +import android.view.WindowManager.TRANSIT_CLOSE +import android.view.WindowManager.TRANSIT_TO_BACK import android.view.animation.PathInterpolator +import android.window.RemoteTransition +import android.window.TransitionFilter import androidx.annotation.AnyThread import androidx.annotation.BinderThread import androidx.annotation.UiThread @@ -44,6 +49,9 @@ import com.android.app.animation.Interpolators import com.android.internal.annotations.VisibleForTesting import com.android.internal.policy.ScreenDecorationsUtils import com.android.systemui.Flags.activityTransitionUseLargestWindow +import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary +import com.android.wm.shell.shared.IShellTransitions +import com.android.wm.shell.shared.ShellTransitions import java.util.concurrent.Executor import kotlin.math.roundToInt @@ -59,6 +67,9 @@ constructor( /** The executor that runs on the main thread. */ private val mainExecutor: Executor, + /** The object used to register ephemeral returns and long-lived transitions. */ + private val transitionRegister: TransitionRegister? = null, + /** The animator used when animating a View into an app. */ private val transitionAnimator: TransitionAnimator = defaultTransitionAnimator(mainExecutor), @@ -74,6 +85,36 @@ constructor( // TODO(b/301385865): Remove this flag. private val disableWmTimeout: Boolean = false, ) { + @JvmOverloads + constructor( + mainExecutor: Executor, + shellTransitions: ShellTransitions, + transitionAnimator: TransitionAnimator = defaultTransitionAnimator(mainExecutor), + dialogToAppAnimator: TransitionAnimator = defaultDialogToAppAnimator(mainExecutor), + disableWmTimeout: Boolean = false, + ) : this( + mainExecutor, + TransitionRegister.fromShellTransitions(shellTransitions), + transitionAnimator, + dialogToAppAnimator, + disableWmTimeout, + ) + + @JvmOverloads + constructor( + mainExecutor: Executor, + iShellTransitions: IShellTransitions, + transitionAnimator: TransitionAnimator = defaultTransitionAnimator(mainExecutor), + dialogToAppAnimator: TransitionAnimator = defaultDialogToAppAnimator(mainExecutor), + disableWmTimeout: Boolean = false, + ) : this( + mainExecutor, + TransitionRegister.fromIShellTransitions(iShellTransitions), + transitionAnimator, + dialogToAppAnimator, + disableWmTimeout, + ) + companion object { /** The timings when animating a View into an app. */ @JvmField @@ -233,6 +274,10 @@ constructor( } } + if (animationAdapter != null && controller.transitionCookie != null) { + registerEphemeralReturnAnimation(controller, transitionRegister) + } + val launchResult = intentStarter(animationAdapter) // Only animate if the app is not already on top and will be opened, unless we are on the @@ -302,6 +347,66 @@ constructor( } } + /** + * Uses [transitionRegister] to set up the return animation for the given [launchController]. + * + * De-registration is set up automatically once the return animation is run. + * + * TODO(b/339194555): automatically de-register when the launchable is detached. + */ + private fun registerEphemeralReturnAnimation( + launchController: Controller, + transitionRegister: TransitionRegister? + ) { + if (!returnAnimationFrameworkLibrary()) return + + var cleanUpRunnable: Runnable? = null + val returnRunner = + createRunner( + object : DelegateTransitionAnimatorController(launchController) { + override val isLaunching = false + + override fun onTransitionAnimationCancelled( + newKeyguardOccludedState: Boolean? + ) { + super.onTransitionAnimationCancelled(newKeyguardOccludedState) + cleanUp() + } + + override fun onTransitionAnimationEnd(isExpandingFullyAbove: Boolean) { + super.onTransitionAnimationEnd(isExpandingFullyAbove) + cleanUp() + } + + private fun cleanUp() { + cleanUpRunnable?.run() + } + } + ) + + // mTypeSet and mModes match back signals only, and not home. This is on purpose, because + // we only want ephemeral return animations triggered in these scenarios. + val filter = + TransitionFilter().apply { + mTypeSet = intArrayOf(TRANSIT_CLOSE, TRANSIT_TO_BACK) + mRequirements = + arrayOf( + TransitionFilter.Requirement().apply { + mLaunchCookie = launchController.transitionCookie + mModes = intArrayOf(TRANSIT_CLOSE, TRANSIT_TO_BACK) + } + ) + } + val transition = + RemoteTransition( + RemoteAnimationRunnerCompat.wrap(returnRunner), + "${launchController.transitionCookie}_returnTransition" + ) + + transitionRegister?.register(filter, transition) + cleanUpRunnable = Runnable { transitionRegister?.unregister(transition) } + } + /** Add a [Listener] that can listen to transition animations. */ fun addListener(listener: Listener) { listeners.add(listener) @@ -386,8 +491,14 @@ constructor( * Note: The background of [view] should be a (rounded) rectangle so that it can be * properly animated. */ + @JvmOverloads @JvmStatic - fun fromView(view: View, cujType: Int? = null): Controller? { + fun fromView( + view: View, + cujType: Int? = null, + cookie: TransitionCookie? = null, + returnCujType: Int? = null + ): Controller? { // Make sure the View we launch from implements LaunchableView to avoid visibility // issues. if (view !is LaunchableView) { @@ -408,7 +519,7 @@ constructor( return null } - return GhostedViewTransitionAnimatorController(view, cujType) + return GhostedViewTransitionAnimatorController(view, cujType, cookie, returnCujType) } } @@ -432,6 +543,17 @@ constructor( get() = false /** + * The cookie associated with the transition controlled by this [Controller]. + * + * This should be defined for all return [Controller] (when [isLaunching] is false) and for + * their associated launch [Controller]s. + * + * For the recommended format, see [TransitionCookie]. + */ + val transitionCookie: TransitionCookie? + get() = null + + /** * The intent was started. If [willAnimate] is false, nothing else will happen and the * animation will not be started. */ @@ -652,7 +774,7 @@ constructor( return } - val window = findRootTaskIfPossible(apps) + val window = findTargetWindowIfPossible(apps) if (window == null) { Log.i(TAG, "Aborting the animation as no window is opening") callback?.invoke() @@ -676,7 +798,7 @@ constructor( startAnimation(window, navigationBar, callback) } - private fun findRootTaskIfPossible( + private fun findTargetWindowIfPossible( apps: Array<out RemoteAnimationTarget>? ): RemoteAnimationTarget? { if (apps == null) { @@ -694,6 +816,19 @@ constructor( for (it in apps) { if (it.mode == targetMode) { if (activityTransitionUseLargestWindow()) { + if (returnAnimationFrameworkLibrary()) { + // If the controller contains a cookie, _only_ match if the candidate + // contains the matching cookie. + if ( + controller.transitionCookie != null && + it.taskInfo + ?.launchCookies + ?.contains(controller.transitionCookie) != true + ) { + continue + } + } + if ( candidate == null || !it.hasAnimatingParent && candidate.hasAnimatingParent @@ -806,11 +941,7 @@ constructor( progress: Float, linearProgress: Float ) { - // Apply the state to the window only if it is visible, i.e. when the - // expanding view is *not* visible. - if (!state.visible) { - applyStateToWindow(window, state, linearProgress) - } + applyStateToWindow(window, state, linearProgress) navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) } listener?.onTransitionAnimationProgress(linearProgress) @@ -1048,4 +1179,72 @@ constructor( return (this.width() * this.height()) > (other.width() * other.height()) } } + + /** + * Wraps one of the two methods we have to register remote transitions with WM Shell: + * - for in-process registrations (e.g. System UI) we use [ShellTransitions] + * - for cross-process registrations (e.g. Launcher) we use [IShellTransitions] + * + * Important: each instance of this class must wrap exactly one of the two. + */ + class TransitionRegister + private constructor( + private val shellTransitions: ShellTransitions? = null, + private val iShellTransitions: IShellTransitions? = null, + ) { + init { + assert((shellTransitions != null).xor(iShellTransitions != null)) + } + + companion object { + /** Provides a [TransitionRegister] instance wrapping [ShellTransitions]. */ + fun fromShellTransitions(shellTransitions: ShellTransitions): TransitionRegister { + return TransitionRegister(shellTransitions = shellTransitions) + } + + /** Provides a [TransitionRegister] instance wrapping [IShellTransitions]. */ + fun fromIShellTransitions(iShellTransitions: IShellTransitions): TransitionRegister { + return TransitionRegister(iShellTransitions = iShellTransitions) + } + } + + /** Register [remoteTransition] with WM Shell using the given [filter]. */ + internal fun register( + filter: TransitionFilter, + remoteTransition: RemoteTransition, + ) { + shellTransitions?.registerRemote(filter, remoteTransition) + iShellTransitions?.registerRemote(filter, remoteTransition) + } + + /** Unregister [remoteTransition] from WM Shell. */ + internal fun unregister(remoteTransition: RemoteTransition) { + shellTransitions?.unregisterRemote(remoteTransition) + iShellTransitions?.unregisterRemote(remoteTransition) + } + } + + /** + * A cookie used to uniquely identify a task launched using an + * [ActivityTransitionAnimator.Controller]. + * + * The [String] encapsulated by this class should be formatted in such a way to be unique across + * the system, but reliably constant for the same associated launchable. + * + * Recommended naming scheme: + * - DO use the fully qualified name of the class that owns the instance of the launchable, + * along with a concise and precise description of the purpose of the launchable in question. + * - DO NOT introduce uniqueness through the use of timestamps or other runtime variables that + * will change if the instance is destroyed and re-created. + * + * Example: "com.not.the.real.class.name.ShadeController_openSettingsButton" + * + * Note that sometimes (e.g. in recycler views) there could be multiple instances of the same + * launchable, and no static knowledge to adequately differentiate between them using a single + * description. In this case, the recommendation is to append a unique identifier related to the + * contents of the launchable. + * + * Example: “com.not.the.real.class.name.ToastWebResult_launchAga_id143256” + */ + data class TransitionCookie(private val cookie: String) : Binder() } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt index e4bb2adbefb4..21557b8bb402 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt @@ -25,10 +25,30 @@ interface Expandable { * [Expandable] into an Activity, or return `null` if this [Expandable] should not be animated * (e.g. if it is currently not attached or visible). * - * @param cujType the CUJ type from the [com.android.internal.jank.InteractionJankMonitor] + * @param launchCujType The CUJ type from the [com.android.internal.jank.InteractionJankMonitor] * associated to the launch that will use this controller. + * @param cookie The unique cookie associated with the launch that will use this controller. + * This is required iff the a return animation should be included. + * @param returnCujType The CUJ type from the [com.android.internal.jank.InteractionJankMonitor] + * associated to the return animation that will use this controller. */ - fun activityTransitionController(cujType: Int? = null): ActivityTransitionAnimator.Controller? + fun activityTransitionController( + launchCujType: Int? = null, + cookie: ActivityTransitionAnimator.TransitionCookie? = null, + returnCujType: Int? = null + ): ActivityTransitionAnimator.Controller? + + /** + * See [activityTransitionController] above. + * + * Interfaces don't support [JvmOverloads], so this is a useful overload for Java usages that + * don't use the return-related parameters. + */ + fun activityTransitionController( + launchCujType: Int? = null + ): ActivityTransitionAnimator.Controller? { + return activityTransitionController(launchCujType, cookie = null, returnCujType = null) + } /** * Create a [DialogTransitionAnimator.Controller] that can be used to expand this [Expandable] @@ -48,9 +68,16 @@ interface Expandable { fun fromView(view: View): Expandable { return object : Expandable { override fun activityTransitionController( - cujType: Int?, + launchCujType: Int?, + cookie: ActivityTransitionAnimator.TransitionCookie?, + returnCujType: Int? ): ActivityTransitionAnimator.Controller? { - return ActivityTransitionAnimator.Controller.fromView(view, cujType) + return ActivityTransitionAnimator.Controller.fromView( + view, + launchCujType, + cookie, + returnCujType + ) } override fun dialogTransitionController( diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt index fd79f62debce..9d4507337e51 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GhostedViewTransitionAnimatorController.kt @@ -59,8 +59,12 @@ constructor( /** The view that will be ghosted and from which the background will be extracted. */ private val ghostedView: View, - /** The [CujType] associated to this animation. */ - private val cujType: Int? = null, + /** The [CujType] associated to this launch animation. */ + private val launchCujType: Int? = null, + override val transitionCookie: ActivityTransitionAnimator.TransitionCookie? = null, + + /** The [CujType] associated to this return animation. */ + private val returnCujType: Int? = null, private var interactionJankMonitor: InteractionJankMonitor = InteractionJankMonitor.getInstance(), ) : ActivityTransitionAnimator.Controller { @@ -104,6 +108,15 @@ constructor( */ private val background: Drawable? + /** CUJ identifier accounting for whether this controller is for a launch or a return. */ + private val cujType: Int? + get() = + if (isLaunching) { + launchCujType + } else { + returnCujType + } + init { // Make sure the View we launch from implements LaunchableView to avoid visibility issues. if (ghostedView !is LaunchableView) { diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CollectAsStateDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CollectAsStateDetector.kt new file mode 100644 index 000000000000..94620c4c73b4 --- /dev/null +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/CollectAsStateDetector.kt @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.systemui.lint + +import com.android.tools.lint.client.api.UElementHandler +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 org.jetbrains.uast.UElement +import org.jetbrains.uast.UFile +import org.jetbrains.uast.UImportStatement + +class CollectAsStateDetector : Detector(), SourceCodeScanner { + + override fun getApplicableUastTypes(): List<Class<out UElement>> { + return listOf(UFile::class.java) + } + + override fun createUastHandler(context: JavaContext): UElementHandler { + return object : UElementHandler() { + override fun visitFile(node: UFile) { + node.imports.forEach { importStatement -> + visitImportStatement(context, importStatement) + } + } + } + } + + private fun visitImportStatement( + context: JavaContext, + importStatement: UImportStatement, + ) { + val importText = importStatement.importReference?.asSourceString() ?: return + if (ILLEGAL_IMPORT == importText) { + context.report( + issue = ISSUE, + scope = importStatement, + location = context.getLocation(importStatement), + message = "collectAsState considered harmful", + ) + } + } + + companion object { + @JvmField + val ISSUE = + Issue.create( + id = "OverlyEagerCollectAsState", + briefDescription = "collectAsState considered harmful", + explanation = + """ + go/sysui-compose#collect-as-state + + Don't use collectAsState as it will set up a coroutine that keeps collecting from a + flow until its coroutine scope becomes inactive. This prevents the work from being + properly paused while the surrounding lifecycle becomes paused or stopped and is + therefore considered harmful. + + Instead, use Flow.collectAsStateWithLifecycle(initial: T) or + StateFlow.collectAsStateWithLifecycle(). These APIs correctly pause the collection + coroutine while the lifecycle drops below the specified minActiveState (which + defaults to STARTED meaning that it will pause when the Compose-hosting window + becomes invisible). + """ + .trimIndent(), + category = Category.PERFORMANCE, + priority = 8, + severity = Severity.ERROR, + implementation = + Implementation( + CollectAsStateDetector::class.java, + Scope.JAVA_FILE_SCOPE, + ), + ) + + private val ILLEGAL_IMPORT = "androidx.compose.runtime.collectAsState" + } +} diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt index cecbc474a18a..73ac6ccf8f76 100644 --- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt @@ -32,6 +32,7 @@ class SystemUIIssueRegistry : IssueRegistry() { BindServiceOnMainThreadDetector.ISSUE, BroadcastSentViaContextDetector.ISSUE, CleanArchitectureDependencyViolationDetector.ISSUE, + CollectAsStateDetector.ISSUE, DumpableNotRegisteredDetector.ISSUE, FlowDetector.SHARED_FLOW_CREATION, SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY, diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CollectAsStateDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CollectAsStateDetectorTest.kt new file mode 100644 index 000000000000..6962b4eb31e6 --- /dev/null +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/CollectAsStateDetectorTest.kt @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.systemui.lint + +import com.android.tools.lint.checks.infrastructure.TestFiles +import com.android.tools.lint.detector.api.Detector +import com.android.tools.lint.detector.api.Issue +import org.junit.Test + +class CollectAsStateDetectorTest : SystemUILintDetectorTest() { + + override fun getDetector(): Detector { + return CollectAsStateDetector() + } + + override fun getIssues(): List<Issue> { + return listOf( + CollectAsStateDetector.ISSUE, + ) + } + + @Test + fun testViolation() { + lint() + .files(COLLECT_AS_STATE_STUB, COLLECT_WITH_LIFECYCLE_AS_STATE_STUB, GOOD_FILE, BAD_FILE) + .issues(CollectAsStateDetector.ISSUE) + .run() + .expect( + """ +src/com/android/internal/systemui/lint/Bad.kt:3: Error: collectAsState considered harmful [OverlyEagerCollectAsState] +import androidx.compose.runtime.collectAsState +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1 errors, 0 warnings + """ + .trimIndent() + ) + } + + @Test + fun testNoViolation() { + lint() + .files(COLLECT_AS_STATE_STUB, COLLECT_WITH_LIFECYCLE_AS_STATE_STUB, GOOD_FILE) + .issues(CollectAsStateDetector.ISSUE) + .run() + .expectClean() + } + + companion object { + private val COLLECT_AS_STATE_STUB = + TestFiles.kotlin( + """ + package androidx.compose.runtime + + fun collectAsState() {} + """ + .trimIndent() + ) + private val COLLECT_WITH_LIFECYCLE_AS_STATE_STUB = + TestFiles.kotlin( + """ + package androidx.lifecycle.compose + + fun collectAsStateWithLifecycle() {} + """ + .trimIndent() + ) + + private val BAD_FILE = + TestFiles.kotlin( + """ + package com.android.internal.systemui.lint + + import androidx.compose.runtime.collectAsState + + class Bad + """ + .trimIndent() + ) + + private val GOOD_FILE = + TestFiles.kotlin( + """ + package com.android.internal.systemui.lint + + import androidx.lifecycle.compose.collectAsStateWithLifecycle + + class Good + """ + .trimIndent() + ) + } +} diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt index c7f0a965206e..17a606171a9e 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/ExpandableController.kt @@ -134,13 +134,15 @@ internal class ExpandableControllerImpl( override val expandable: Expandable = object : Expandable { override fun activityTransitionController( - cujType: Int?, + launchCujType: Int?, + cookie: ActivityTransitionAnimator.TransitionCookie?, + returnCujType: Int? ): ActivityTransitionAnimator.Controller? { if (!isComposed.value) { return null } - return activityController(cujType) + return activityController(launchCujType, cookie, returnCujType) } override fun dialogTransitionController( @@ -262,10 +264,27 @@ internal class ExpandableControllerImpl( } /** Create an [ActivityTransitionAnimator.Controller] that can be used to animate activities. */ - private fun activityController(cujType: Int?): ActivityTransitionAnimator.Controller { + private fun activityController( + launchCujType: Int?, + cookie: ActivityTransitionAnimator.TransitionCookie?, + returnCujType: Int? + ): ActivityTransitionAnimator.Controller { val delegate = transitionController() return object : ActivityTransitionAnimator.Controller, TransitionAnimator.Controller by delegate { + /** + * CUJ identifier accounting for whether this controller is for a launch or a return. + */ + private val cujType: Int? + get() = + if (isLaunching) { + launchCujType + } else { + returnCujType + } + + override val transitionCookie = cookie + override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) { delegate.onTransitionAnimationStart(isExpandingFullyAbove) overlay.value = composeViewRoot.rootView.overlay as ViewGroupOverlay diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt index c22b50d9dd64..fa01a4bf46c5 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerContent.kt @@ -56,7 +56,6 @@ import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -77,6 +76,7 @@ import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.times +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.PlatformButton import com.android.compose.animation.Easings import com.android.compose.animation.scene.ElementKey @@ -111,7 +111,7 @@ fun BouncerContent( dialogFactory: BouncerDialogFactory, modifier: Modifier = Modifier, ) { - val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsState() + val isSideBySideSupported by viewModel.isSideBySideSupported.collectAsStateWithLifecycle() val layout = calculateLayout(isSideBySideSupported = isSideBySideSupported) Box( @@ -220,7 +220,7 @@ private fun SplitLayout( viewModel: BouncerViewModel, modifier: Modifier = Modifier, ) { - val authMethod by viewModel.authMethodViewModel.collectAsState() + val authMethod by viewModel.authMethodViewModel.collectAsStateWithLifecycle() Row( modifier = @@ -316,7 +316,7 @@ private fun BesideUserSwitcherLayout( val (isSwapped, setSwapped) = rememberSaveable(isLeftToRight) { mutableStateOf(!isLeftToRight) } val isHeightExpanded = LocalWindowSizeClass.current.heightSizeClass == WindowHeightSizeClass.Expanded - val authMethod by viewModel.authMethodViewModel.collectAsState() + val authMethod by viewModel.authMethodViewModel.collectAsStateWithLifecycle() Row( modifier = @@ -480,7 +480,7 @@ private fun FoldAware( modifier: Modifier = Modifier, ) { val foldPosture: FoldPosture by foldPosture() - val isSplitAroundTheFoldRequired by viewModel.isFoldSplitRequired.collectAsState() + val isSplitAroundTheFoldRequired by viewModel.isFoldSplitRequired.collectAsStateWithLifecycle() val isSplitAroundTheFold = foldPosture == FoldPosture.Tabletop && isSplitAroundTheFoldRequired val currentSceneKey = if (isSplitAroundTheFold) SceneKeys.SplitSceneKey else SceneKeys.ContiguousSceneKey @@ -562,7 +562,7 @@ private fun StatusMessage( viewModel: BouncerMessageViewModel, modifier: Modifier = Modifier, ) { - val message: MessageViewModel? by viewModel.message.collectAsState() + val message: MessageViewModel? by viewModel.message.collectAsStateWithLifecycle() DisposableEffect(Unit) { viewModel.onShown() @@ -612,7 +612,7 @@ private fun OutputArea( modifier: Modifier = Modifier, ) { val authMethodViewModel: AuthMethodBouncerViewModel? by - viewModel.authMethodViewModel.collectAsState() + viewModel.authMethodViewModel.collectAsStateWithLifecycle() when (val nonNullViewModel = authMethodViewModel) { is PinBouncerViewModel -> @@ -642,7 +642,7 @@ private fun InputArea( modifier: Modifier = Modifier, ) { val authMethodViewModel: AuthMethodBouncerViewModel? by - viewModel.authMethodViewModel.collectAsState() + viewModel.authMethodViewModel.collectAsStateWithLifecycle() when (val nonNullViewModel = authMethodViewModel) { is PinBouncerViewModel -> { @@ -668,7 +668,8 @@ private fun ActionArea( viewModel: BouncerViewModel, modifier: Modifier = Modifier, ) { - val actionButton: BouncerActionButtonModel? by viewModel.actionButton.collectAsState() + val actionButton: BouncerActionButtonModel? by + viewModel.actionButton.collectAsStateWithLifecycle() val appearFadeInAnimatable = remember { Animatable(0f) } val appearMoveAnimatable = remember { Animatable(0f) } val appearAnimationInitialOffset = with(LocalDensity.current) { 80.dp.toPx() } @@ -735,7 +736,7 @@ private fun Dialog( bouncerViewModel: BouncerViewModel, dialogFactory: BouncerDialogFactory, ) { - val dialogViewModel by bouncerViewModel.dialogViewModel.collectAsState() + val dialogViewModel by bouncerViewModel.dialogViewModel.collectAsStateWithLifecycle() var dialog: AlertDialog? by remember { mutableStateOf(null) } dialogViewModel?.let { viewModel -> @@ -772,8 +773,8 @@ private fun UserSwitcher( return } - val selectedUserImage by viewModel.selectedUserImage.collectAsState(null) - val dropdownItems by viewModel.userSwitcherDropdown.collectAsState(emptyList()) + val selectedUserImage by viewModel.selectedUserImage.collectAsStateWithLifecycle(null) + val dropdownItems by viewModel.userSwitcherDropdown.collectAsStateWithLifecycle(emptyList()) Column( horizontalAlignment = Alignment.CenterHorizontally, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt index 2dcd0ff05c73..203bd7a69a7a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PasswordBouncer.kt @@ -27,7 +27,6 @@ import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.ExperimentalComposeUiApi @@ -49,6 +48,7 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.PlatformIconButton import com.android.systemui.bouncer.ui.viewmodel.PasswordBouncerViewModel import com.android.systemui.common.ui.compose.SelectedUserAwareInputConnection @@ -62,18 +62,20 @@ internal fun PasswordBouncer( modifier: Modifier = Modifier, ) { val focusRequester = remember { FocusRequester() } - val isTextFieldFocusRequested by viewModel.isTextFieldFocusRequested.collectAsState() + val isTextFieldFocusRequested by + viewModel.isTextFieldFocusRequested.collectAsStateWithLifecycle() LaunchedEffect(isTextFieldFocusRequested) { if (isTextFieldFocusRequested) { focusRequester.requestFocus() } } - val password: String by viewModel.password.collectAsState() - val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState() - val animateFailure: Boolean by viewModel.animateFailure.collectAsState() - val isImeSwitcherButtonVisible by viewModel.isImeSwitcherButtonVisible.collectAsState() - val selectedUserId by viewModel.selectedUserId.collectAsState() + val password: String by viewModel.password.collectAsStateWithLifecycle() + val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsStateWithLifecycle() + val animateFailure: Boolean by viewModel.animateFailure.collectAsStateWithLifecycle() + val isImeSwitcherButtonVisible by + viewModel.isImeSwitcherButtonVisible.collectAsStateWithLifecycle() + val selectedUserId by viewModel.selectedUserId.collectAsStateWithLifecycle() DisposableEffect(Unit) { onDispose { viewModel.onHidden() } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt index d7e9c10e7224..9c2fd64052b4 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PatternBouncer.kt @@ -30,7 +30,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -47,6 +46,7 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.integerResource import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.Easings import com.android.compose.modifiers.thenIf import com.android.internal.R @@ -86,14 +86,15 @@ internal fun PatternBouncer( val lineStrokeWidth = with(density) { LINE_STROKE_WIDTH_DP.dp.toPx() } // All dots that should be rendered on the grid. - val dots: List<PatternDotViewModel> by viewModel.dots.collectAsState() + val dots: List<PatternDotViewModel> by viewModel.dots.collectAsStateWithLifecycle() // The most recently selected dot, if the user is currently dragging. - val currentDot: PatternDotViewModel? by viewModel.currentDot.collectAsState() + val currentDot: PatternDotViewModel? by viewModel.currentDot.collectAsStateWithLifecycle() // The dots selected so far, if the user is currently dragging. - val selectedDots: List<PatternDotViewModel> by viewModel.selectedDots.collectAsState() - val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState() - val isAnimationEnabled: Boolean by viewModel.isPatternVisible.collectAsState() - val animateFailure: Boolean by viewModel.animateFailure.collectAsState() + val selectedDots: List<PatternDotViewModel> by + viewModel.selectedDots.collectAsStateWithLifecycle() + val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsStateWithLifecycle() + val isAnimationEnabled: Boolean by viewModel.isPatternVisible.collectAsStateWithLifecycle() + val animateFailure: Boolean by viewModel.animateFailure.collectAsStateWithLifecycle() // Map of animatables for the scale of each dot, keyed by dot. val dotScalingAnimatables = remember(dots) { dots.associateWith { Animatable(1f) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt index 5651a4646b2d..64ace2f18372 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinBouncer.kt @@ -33,7 +33,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -49,6 +48,7 @@ import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalView import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.Easings import com.android.compose.grid.VerticalGrid import com.android.compose.modifiers.thenIf @@ -74,12 +74,13 @@ fun PinPad( ) { DisposableEffect(Unit) { onDispose { viewModel.onHidden() } } - val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsState() - val backspaceButtonAppearance by viewModel.backspaceButtonAppearance.collectAsState() - val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsState() - val animateFailure: Boolean by viewModel.animateFailure.collectAsState() + val isInputEnabled: Boolean by viewModel.isInputEnabled.collectAsStateWithLifecycle() + val backspaceButtonAppearance by + viewModel.backspaceButtonAppearance.collectAsStateWithLifecycle() + val confirmButtonAppearance by viewModel.confirmButtonAppearance.collectAsStateWithLifecycle() + val animateFailure: Boolean by viewModel.animateFailure.collectAsStateWithLifecycle() val isDigitButtonAnimationEnabled: Boolean by - viewModel.isDigitButtonAnimationEnabled.collectAsState() + viewModel.isDigitButtonAnimationEnabled.collectAsStateWithLifecycle() val buttonScaleAnimatables = remember { List(12) { Animatable(1f) } } LaunchedEffect(animateFailure) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt index 1a97912c77bb..465eade4e169 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/PinInputDisplay.kt @@ -42,7 +42,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateListOf @@ -65,6 +64,7 @@ import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.PlatformOutlinedButton import com.android.compose.animation.Easings import com.android.keyguard.PinShapeAdapter @@ -86,7 +86,7 @@ fun PinInputDisplay( viewModel: PinBouncerViewModel, modifier: Modifier = Modifier, ) { - val hintedPinLength: Int? by viewModel.hintedPinLength.collectAsState() + val hintedPinLength: Int? by viewModel.hintedPinLength.collectAsStateWithLifecycle() val shapeAnimations = rememberShapeAnimations(viewModel.pinShapes) // The display comes in two different flavors: @@ -119,7 +119,7 @@ private fun HintingPinInputDisplay( hintedPinLength: Int, modifier: Modifier = Modifier, ) { - val pinInput: PinInputViewModel by viewModel.pinInput.collectAsState() + val pinInput: PinInputViewModel by viewModel.pinInput.collectAsStateWithLifecycle() // [ClearAll] marker pointing at the beginning of the current pin input. // When a new [ClearAll] token is added to the [pinInput], the clear-all animation is played // and the marker is advanced manually to the most recent marker. See LaunchedEffect below. @@ -257,9 +257,10 @@ private fun RegularPinInputDisplay( @Composable private fun SimArea(viewModel: PinBouncerViewModel) { - val isLockedEsim by viewModel.isLockedEsim.collectAsState() - val isSimUnlockingDialogVisible by viewModel.isSimUnlockingDialogVisible.collectAsState() - val errorDialogMessage by viewModel.errorDialogMessage.collectAsState() + val isLockedEsim by viewModel.isLockedEsim.collectAsStateWithLifecycle() + val isSimUnlockingDialogVisible by + viewModel.isSimUnlockingDialogVisible.collectAsStateWithLifecycle() + val errorDialogMessage by viewModel.errorDialogMessage.collectAsStateWithLifecycle() var unlockDialog: Dialog? by remember { mutableStateOf(null) } var errorDialog: Dialog? by remember { mutableStateOf(null) } val context = LocalView.current.context diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt index c8e145034551..694326d0549c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/SelectedUserAwareInputConnection.kt @@ -35,7 +35,7 @@ import androidx.compose.ui.platform.PlatformTextInputMethodRequest * ``` * @Composable * fun YourFunction(viewModel: YourViewModel) { - * val selectedUserId by viewModel.selectedUserId.collectAsState() + * val selectedUserId by viewModel.selectedUserId.collectAsStateWithLifecycle() * * SelectedUserAwareInputConnection(selectedUserId) { * TextField(...) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt index 8144d15020fa..296fc27ac0ff 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/windowinsets/ScreenDecorProvider.kt @@ -22,12 +22,12 @@ import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.systemBars import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.flow.StateFlow /** The bounds and [CutoutLocation] of the current display. */ @@ -45,7 +45,7 @@ fun ScreenDecorProvider( screenCornerRadius: Float, content: @Composable () -> Unit, ) { - val cutout by displayCutout.collectAsState() + val cutout by displayCutout.collectAsStateWithLifecycle() val screenCornerRadiusDp = with(LocalDensity.current) { screenCornerRadius.toDp() } val density = LocalDensity.current diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt index ec3c0030c44f..8ee8ea4b4f4c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt @@ -6,15 +6,16 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.dimensionResource +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.ElementKey +import com.android.compose.animation.scene.ElementMatcher import com.android.compose.animation.scene.FixedSizeEdgeDetector import com.android.compose.animation.scene.LowestZIndexScenePicker import com.android.compose.animation.scene.MutableSceneTransitionLayoutState @@ -33,33 +34,38 @@ import com.android.systemui.communal.util.CommunalColors import com.android.systemui.res.R import com.android.systemui.scene.shared.model.SceneDataSourceDelegator import com.android.systemui.scene.ui.composable.SceneTransitionLayoutDataSource -import com.android.systemui.statusbar.phone.SystemUIDialogFactory object Communal { object Elements { val Scrim = ElementKey("Scrim", scenePicker = LowestZIndexScenePicker) - val Content = ElementKey("CommunalContent") + val Grid = ElementKey("CommunalContent") + val LockIcon = ElementKey("CommunalLockIcon") + val IndicationArea = ElementKey("CommunalIndicationArea") } } +object AllElements : ElementMatcher { + override fun matches(key: ElementKey, scene: SceneKey) = true +} + val sceneTransitions = transitions { to(CommunalScenes.Communal, key = CommunalTransitionKeys.SimpleFade) { spec = tween(durationMillis = 250) - fade(Communal.Elements.Scrim) - fade(Communal.Elements.Content) + fade(AllElements) } to(CommunalScenes.Communal) { spec = tween(durationMillis = 1000) - translate(Communal.Elements.Content, Edge.Right) - timestampRange(startMillis = 167, endMillis = 334) { - fade(Communal.Elements.Scrim) - fade(Communal.Elements.Content) - } + translate(Communal.Elements.Grid, Edge.Right) + timestampRange(startMillis = 167, endMillis = 334) { fade(AllElements) } } to(CommunalScenes.Blank) { spec = tween(durationMillis = 1000) - translate(Communal.Elements.Content, Edge.Right) - timestampRange(endMillis = 167) { fade(Communal.Elements.Content) } + translate(Communal.Elements.Grid, Edge.Right) + timestampRange(endMillis = 167) { + fade(Communal.Elements.Grid) + fade(Communal.Elements.IndicationArea) + fade(Communal.Elements.LockIcon) + } timestampRange(startMillis = 167, endMillis = 334) { fade(Communal.Elements.Scrim) } } } @@ -75,12 +81,13 @@ fun CommunalContainer( modifier: Modifier = Modifier, viewModel: CommunalViewModel, dataSourceDelegator: SceneDataSourceDelegator, - dialogFactory: SystemUIDialogFactory, colors: CommunalColors, + content: CommunalContent, ) { val coroutineScope = rememberCoroutineScope() - val currentSceneKey: SceneKey by viewModel.currentScene.collectAsState(CommunalScenes.Blank) - val touchesAllowed by viewModel.touchesAllowed.collectAsState(initial = false) + val currentSceneKey: SceneKey by + viewModel.currentScene.collectAsStateWithLifecycle(CommunalScenes.Blank) + val touchesAllowed by viewModel.touchesAllowed.collectAsStateWithLifecycle(initialValue = false) val state: MutableSceneTransitionLayoutState = remember { MutableSceneTransitionLayoutState( initialScene = currentSceneKey, @@ -127,7 +134,7 @@ fun CommunalContainer( userActions = mapOf(Swipe(SwipeDirection.Right, fromSource = Edge.Left) to CommunalScenes.Blank) ) { - CommunalScene(viewModel, colors, dialogFactory, modifier = modifier) + CommunalScene(colors, content) } } @@ -139,12 +146,11 @@ fun CommunalContainer( /** Scene containing the glanceable hub UI. */ @Composable private fun SceneScope.CommunalScene( - viewModel: CommunalViewModel, colors: CommunalColors, - dialogFactory: SystemUIDialogFactory, + content: CommunalContent, modifier: Modifier = Modifier, ) { - val backgroundColor by colors.backgroundColor.collectAsState() + val backgroundColor by colors.backgroundColor.collectAsStateWithLifecycle() Box( modifier = @@ -152,7 +158,5 @@ private fun SceneScope.CommunalScene( .fillMaxSize() .background(Color(backgroundColor.toArgb())), ) - Box(modifier.element(Communal.Elements.Content)) { - CommunalHub(viewModel = viewModel, dialogFactory = dialogFactory) - } + with(content) { Content(modifier = modifier) } } 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 new file mode 100644 index 000000000000..776651558e48 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.communal.ui.compose + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.Layout +import androidx.compose.ui.unit.IntRect +import com.android.compose.animation.scene.SceneScope +import com.android.compose.theme.LocalAndroidColorScheme +import com.android.systemui.communal.ui.viewmodel.CommunalViewModel +import com.android.systemui.keyguard.ui.composable.blueprint.BlueprintAlignmentLines +import com.android.systemui.keyguard.ui.composable.section.LockSection +import com.android.systemui.statusbar.phone.SystemUIDialogFactory +import javax.inject.Inject + +/** Renders the content of the glanceable hub. */ +class CommunalContent +@Inject +constructor( + private val viewModel: CommunalViewModel, + private val dialogFactory: SystemUIDialogFactory, + private val lockSection: LockSection, +) { + + @Composable + fun SceneScope.Content(modifier: Modifier = Modifier) { + Layout( + modifier = modifier.fillMaxSize(), + content = { + CommunalHub( + viewModel = viewModel, + dialogFactory = dialogFactory, + modifier = Modifier.element(Communal.Elements.Grid) + ) + with(lockSection) { + LockIcon( + overrideColor = LocalAndroidColorScheme.current.onPrimaryContainer, + modifier = Modifier.element(Communal.Elements.LockIcon) + ) + } + } + ) { measurables, constraints -> + val communalGridMeasurable = measurables[0] + val lockIconMeasurable = measurables[1] + + val noMinConstraints = + constraints.copy( + minWidth = 0, + minHeight = 0, + ) + + val lockIconPlaceable = lockIconMeasurable.measure(noMinConstraints) + val lockIconBounds = + IntRect( + left = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Left], + top = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Top], + right = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Right], + bottom = lockIconPlaceable[BlueprintAlignmentLines.LockIcon.Bottom], + ) + + val communalGridPlaceable = + communalGridMeasurable.measure( + noMinConstraints.copy(maxHeight = lockIconBounds.top) + ) + + layout(constraints.maxWidth, constraints.maxHeight) { + communalGridPlaceable.place( + x = 0, + y = 0, + ) + lockIconPlaceable.place( + x = lockIconBounds.left, + y = lockIconBounds.top, + ) + } + } + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt index 6fe5cef8b1e3..2a52c60c820e 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt @@ -78,7 +78,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -108,7 +107,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.CustomAccessibilityAction import androidx.compose.ui.semantics.contentDescription @@ -125,6 +123,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.window.Popup import androidx.core.view.setPadding +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.window.layout.WindowMetricsCalculator import com.android.compose.modifiers.thenIf import com.android.compose.theme.LocalAndroidColorScheme @@ -157,20 +156,21 @@ fun CommunalHub( onOpenWidgetPicker: (() -> Unit)? = null, onEditDone: (() -> Unit)? = null, ) { - val communalContent by viewModel.communalContent.collectAsState(initial = emptyList()) - val currentPopup by viewModel.currentPopup.collectAsState(initial = null) + val communalContent by + viewModel.communalContent.collectAsStateWithLifecycle(initialValue = emptyList()) + val currentPopup by viewModel.currentPopup.collectAsStateWithLifecycle(initialValue = null) var removeButtonCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) } var toolbarSize: IntSize? by remember { mutableStateOf(null) } var gridCoordinates: LayoutCoordinates? by remember { mutableStateOf(null) } var isDraggingToRemove by remember { mutableStateOf(false) } val gridState = rememberLazyGridState() val contentListState = rememberContentListState(widgetConfigurator, communalContent, viewModel) - val reorderingWidgets by viewModel.reorderingWidgets.collectAsState() - val selectedKey = viewModel.selectedKey.collectAsState() + val reorderingWidgets by viewModel.reorderingWidgets.collectAsStateWithLifecycle() + val selectedKey = viewModel.selectedKey.collectAsStateWithLifecycle() val removeButtonEnabled by remember { derivedStateOf { selectedKey.value != null || reorderingWidgets } } - val isEmptyState by viewModel.isEmptyState.collectAsState(initial = false) + val isEmptyState by viewModel.isEmptyState.collectAsStateWithLifecycle(initialValue = false) val contentPadding = gridContentPadding(viewModel.isEditMode, toolbarSize) val contentOffset = beforeContentPadding(contentPadding).toOffset() @@ -265,17 +265,6 @@ fun CommunalHub( } } - // TODO(b/326060686): Remove this once keyguard indication area can persist over hub - if (viewModel is CommunalViewModel) { - val isUnlocked by viewModel.deviceUnlocked.collectAsState(initial = false) - LockStateIcon( - modifier = - Modifier.align(Alignment.BottomCenter) - .padding(bottom = Dimensions.LockIconBottomPadding), - isUnlocked = isUnlocked, - ) - } - if (viewModel.isEditMode && onOpenWidgetPicker != null && onEditDone != null) { Toolbar( setToolbarSize = { toolbarSize = it }, @@ -315,9 +304,9 @@ fun CommunalHub( if (viewModel is CommunalViewModel && dialogFactory != null) { val isEnableWidgetDialogShowing by - viewModel.isEnableWidgetDialogShowing.collectAsState(false) + viewModel.isEnableWidgetDialogShowing.collectAsStateWithLifecycle(false) val isEnableWorkProfileDialogShowing by - viewModel.isEnableWorkProfileDialogShowing.collectAsState(false) + viewModel.isEnableWorkProfileDialogShowing.collectAsStateWithLifecycle(false) EnableWidgetDialog( isEnableWidgetDialogVisible = isEnableWidgetDialogShowing, @@ -549,26 +538,6 @@ private fun EmptyStateCta( } } -@Composable -private fun LockStateIcon( - isUnlocked: Boolean, - modifier: Modifier = Modifier, -) { - val colors = LocalAndroidColorScheme.current - val resource = - if (isUnlocked) { - R.drawable.ic_unlocked - } else { - R.drawable.ic_lock - } - Icon( - painter = painterResource(id = resource), - contentDescription = null, - tint = colors.onPrimaryContainer, - modifier = modifier.size(Dimensions.LockIconSize), - ) -} - /** * Toolbar that contains action buttons to * 1) open the widget picker @@ -892,7 +861,7 @@ private fun WidgetContent( contentListState: ContentListState, ) { val context = LocalContext.current - val isFocusable by viewModel.isFocusable.collectAsState(initial = false) + val isFocusable by viewModel.isFocusable.collectAsStateWithLifecycle(initialValue = false) val accessibilityLabel = remember(model, context) { model.providerInfo.loadLabel(context.packageManager).toString().trim() @@ -900,7 +869,7 @@ private fun WidgetContent( val clickActionLabel = stringResource(R.string.accessibility_action_label_select_widget) val removeWidgetActionLabel = stringResource(R.string.accessibility_action_label_remove_widget) val placeWidgetActionLabel = stringResource(R.string.accessibility_action_label_place_widget) - val selectedKey by viewModel.selectedKey.collectAsState() + val selectedKey by viewModel.selectedKey.collectAsStateWithLifecycle() val selectedIndex = selectedKey?.let { key -> contentListState.list.indexOfFirst { it.key == key } } Box( @@ -1141,7 +1110,7 @@ private fun Umo(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier) @Composable fun AccessibilityContainer(viewModel: BaseCommunalViewModel, content: @Composable () -> Unit) { val context = LocalContext.current - val isFocusable by viewModel.isFocusable.collectAsState(initial = false) + val isFocusable by viewModel.isFocusable.collectAsStateWithLifecycle(initialValue = false) Box( modifier = Modifier.fillMaxWidth().wrapContentHeight().thenIf( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt b/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt index e77ade91a93b..17dac7e2e6d5 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/fold/ui/composable/FoldPosture.kt @@ -18,11 +18,11 @@ package com.android.systemui.fold.ui.composable import androidx.compose.runtime.Composable import androidx.compose.runtime.State -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.window.layout.WindowInfoTracker import com.android.systemui.fold.ui.helper.FoldPosture import com.android.systemui.fold.ui.helper.foldPostureInternal @@ -32,7 +32,8 @@ import com.android.systemui.fold.ui.helper.foldPostureInternal fun foldPosture(): State<FoldPosture> { val context = LocalContext.current val infoTracker = remember(context) { WindowInfoTracker.getOrCreate(context) } - val layoutInfo by infoTracker.windowLayoutInfo(context).collectAsState(initial = null) + val layoutInfo by + infoTracker.windowLayoutInfo(context).collectAsStateWithLifecycle(initialValue = null) return produceState<FoldPosture>( initialValue = FoldPosture.Folded, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt index a8d801abdcd0..67840c7fc696 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt @@ -29,7 +29,6 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.ui.Alignment @@ -37,6 +36,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.theme.PlatformTheme import com.android.systemui.keyboard.stickykeys.shared.model.Locked import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey @@ -57,7 +57,7 @@ fun createStickyKeyIndicatorView(context: Context, viewModel: StickyKeysIndicato @Composable fun StickyKeysIndicator(viewModel: StickyKeysIndicatorViewModel) { - val stickyKeys by viewModel.indicatorContent.collectAsState(emptyMap()) + val stickyKeys by viewModel.indicatorContent.collectAsStateWithLifecycle(emptyMap()) StickyKeysIndicator(stickyKeys) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt index 4bef9efe79d1..6d8c47d84850 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenContent.kt @@ -18,11 +18,11 @@ package com.android.systemui.keyguard.ui.composable import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalView +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint @@ -51,7 +51,7 @@ constructor( modifier: Modifier = Modifier, ) { val coroutineScope = rememberCoroutineScope() - val blueprintId by viewModel.blueprintId(coroutineScope).collectAsState() + val blueprintId by viewModel.blueprintId(coroutineScope).collectAsStateWithLifecycle() val view = LocalView.current DisposableEffect(view) { clockInteractor.clockEventController.registerListeners(view) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt index 472484aa74d9..4555f13a1a2c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenLongPress.kt @@ -26,13 +26,13 @@ import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxScope import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Rect import androidx.compose.ui.input.pointer.pointerInput +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel /** Container for lockscreen content that handles long-press to bring up the settings menu. */ @@ -42,7 +42,8 @@ fun LockscreenLongPress( modifier: Modifier = Modifier, content: @Composable BoxScope.(onSettingsMenuPlaces: (coordinates: Rect?) -> Unit) -> Unit, ) { - val isEnabled: Boolean by viewModel.isLongPressHandlingEnabled.collectAsState(initial = false) + val isEnabled: Boolean by + viewModel.isLongPressHandlingEnabled.collectAsStateWithLifecycle(initialValue = false) val (settingsMenuBounds, setSettingsMenuBounds) = remember { mutableStateOf<Rect?>(null) } val interactionSource = remember { MutableInteractionSource() } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt index 8129e41b4977..ba25719f1d60 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/BurnInState.kt @@ -21,11 +21,11 @@ import androidx.compose.foundation.layout.displayCutout import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.union import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalDensity +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.plugins.clocks.ClockController @@ -37,7 +37,7 @@ import kotlin.math.roundToInt fun rememberBurnIn( clockInteractor: KeyguardClockInteractor, ): BurnInState { - val clock by clockInteractor.currentClock.collectAsState() + val clock by clockInteractor.currentClock.collectAsStateWithLifecycle() val (smartspaceTop, onSmartspaceTopChanged) = remember { mutableStateOf<Float?>(null) } val (smallClockTop, onSmallClockTopChanged) = remember { mutableStateOf<Float?>(null) } 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 315253524b61..abff93d15c55 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 @@ -22,13 +22,13 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.IntRect +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.compose.modifiers.padding import com.android.systemui.keyguard.ui.composable.LockscreenLongPress @@ -67,8 +67,8 @@ constructor( override fun SceneScope.Content(modifier: Modifier) { val isUdfpsVisible = viewModel.isUdfpsVisible val shouldUseSplitNotificationShade by - viewModel.shouldUseSplitNotificationShade.collectAsState() - val unfoldTranslations by viewModel.unfoldTranslations.collectAsState() + viewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle() + val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle() LockscreenLongPress( viewModel = viewModel.longPress, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt index 9d31955122eb..c83f62c4281c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/blueprint/ShortcutsBesideUdfpsBlueprint.kt @@ -22,13 +22,13 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.Layout import androidx.compose.ui.unit.IntRect +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.compose.modifiers.padding import com.android.systemui.keyguard.ui.composable.LockscreenLongPress @@ -70,8 +70,8 @@ constructor( override fun SceneScope.Content(modifier: Modifier) { val isUdfpsVisible = viewModel.isUdfpsVisible val shouldUseSplitNotificationShade by - viewModel.shouldUseSplitNotificationShade.collectAsState() - val unfoldTranslations by viewModel.unfoldTranslations.collectAsState() + viewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle() + val unfoldTranslations by viewModel.unfoldTranslations.collectAsStateWithLifecycle() LockscreenLongPress( viewModel = viewModel.longPress, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt index c109e517a581..aaf49ff00aca 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/modifier/BurnInModifiers.kt @@ -17,7 +17,6 @@ package com.android.systemui.keyguard.ui.composable.modifier import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -25,6 +24,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onPlaced +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel import com.android.systemui.keyguard.ui.viewmodel.BurnInParameters import com.android.systemui.keyguard.ui.viewmodel.BurnInScaleViewModel @@ -44,8 +44,10 @@ fun Modifier.burnInAware( val translationYState = remember { mutableStateOf(0F) } val copiedParams = params.copy(translationY = { translationYState.value }) val burnIn = viewModel.movement(copiedParams) - val translationX by burnIn.map { it.translationX.toFloat() }.collectAsState(initial = 0f) - val translationY by burnIn.map { it.translationY.toFloat() }.collectAsState(initial = 0f) + val translationX by + burnIn.map { it.translationX.toFloat() }.collectAsStateWithLifecycle(initialValue = 0f) + val translationY by + burnIn.map { it.translationY.toFloat() }.collectAsStateWithLifecycle(initialValue = 0f) translationYState.value = translationY val scaleViewModel by burnIn @@ -55,18 +57,14 @@ fun Modifier.burnInAware( scaleClockOnly = it.scaleClockOnly, ) } - .collectAsState(initial = BurnInScaleViewModel()) + .collectAsStateWithLifecycle(initialValue = BurnInScaleViewModel()) return this.graphicsLayer { - val scale = - when { - scaleViewModel.scaleClockOnly && isClock -> scaleViewModel.scale - else -> 1f - } - this.translationX = if (isClock) 0F else translationX this.translationY = translationY this.alpha = alpha + + val scale = if (scaleViewModel.scaleClockOnly) scaleViewModel.scale else 1f this.scaleX = scale this.scaleY = scale } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt index 09ec76df3aea..218779da20b9 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/DefaultClockSection.kt @@ -25,13 +25,13 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.contains +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.compose.modifiers.padding import com.android.systemui.customization.R @@ -59,9 +59,11 @@ constructor( onTopChanged: (top: Float?) -> Unit, modifier: Modifier = Modifier, ) { - val currentClock by viewModel.currentClock.collectAsState() + val currentClock by viewModel.currentClock.collectAsStateWithLifecycle() val smallTopMargin by - viewModel.smallClockTopMargin.collectAsState(viewModel.getSmallClockTopMargin()) + viewModel.smallClockTopMargin.collectAsStateWithLifecycle( + viewModel.getSmallClockTopMargin() + ) if (currentClock?.smallClock?.view == null) { return } @@ -89,7 +91,7 @@ constructor( @Composable fun SceneScope.LargeClock(burnInParams: BurnInParameters, modifier: Modifier = Modifier) { - val currentClock by viewModel.currentClock.collectAsState() + val currentClock by viewModel.currentClock.collectAsStateWithLifecycle() if (currentClock?.largeClock?.view == null) { return } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt index 9f02201f1d81..4129c25901e5 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/LockSection.kt @@ -22,6 +22,7 @@ import android.view.View import android.view.WindowManager import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.Constraints @@ -68,7 +69,7 @@ constructor( private val notificationPanelView: NotificationPanelView, ) { @Composable - fun SceneScope.LockIcon(modifier: Modifier = Modifier) { + fun SceneScope.LockIcon(overrideColor: Color? = null, modifier: Modifier = Modifier) { if (!KeyguardBottomAreaRefactor.isEnabled && !DeviceEntryUdfpsRefactor.isEnabled) { return } @@ -93,6 +94,7 @@ constructor( deviceEntryBackgroundViewModel.get(), falsingManager.get(), vibratorHelper.get(), + overrideColor, ) } } else { 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 556bbbe9f997..3ca2b9c1d86c 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 @@ -18,9 +18,11 @@ package com.android.systemui.keyguard.ui.composable.section import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope -import com.android.systemui.keyguard.ui.viewmodel.MediaCarouselViewModel +import com.android.systemui.keyguard.ui.viewmodel.KeyguardMediaViewModel 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 @@ -33,20 +35,15 @@ class MediaCarouselSection constructor( private val mediaCarouselController: MediaCarouselController, @param:Named(MediaModule.KEYGUARD) private val mediaHost: MediaHost, - private val mediaCarouselViewModel: MediaCarouselViewModel, + private val keyguardMediaViewModel: KeyguardMediaViewModel, ) { - private fun isVisible(): Boolean { - if (mediaCarouselController.mediaFrame == null) { - return false - } - return mediaCarouselViewModel.isMediaVisible - } - @Composable fun SceneScope.KeyguardMediaCarousel() { + val isMediaVisible by keyguardMediaViewModel.isMediaVisible.collectAsStateWithLifecycle() + MediaCarousel( - isVisible = ::isVisible, + isVisible = isMediaVisible, mediaHost = mediaHost, modifier = Modifier.fillMaxWidth(), 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 f48fa88b9722..7f80dfa703bc 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 @@ -20,13 +20,13 @@ import android.view.ViewGroup import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.compose.modifiers.thenIf import com.android.systemui.Flags @@ -40,16 +40,19 @@ import com.android.systemui.notifications.ui.composable.ConstrainedNotificationS import com.android.systemui.res.R import com.android.systemui.shade.LargeScreenHeaderHelper 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 import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel +import dagger.Lazy import javax.inject.Inject @SysUISingleton class NotificationSection @Inject constructor( + private val stackScrollView: Lazy<NotificationScrollView>, private val viewModel: NotificationsPlaceholderViewModel, private val aodBurnInViewModel: AodBurnInViewModel, sharedNotificationContainer: SharedNotificationContainer, @@ -88,9 +91,9 @@ constructor( @Composable fun SceneScope.Notifications(burnInParams: BurnInParameters?, modifier: Modifier = Modifier) { val shouldUseSplitNotificationShade by - lockscreenContentViewModel.shouldUseSplitNotificationShade.collectAsState() + lockscreenContentViewModel.shouldUseSplitNotificationShade.collectAsStateWithLifecycle() val areNotificationsVisible by - lockscreenContentViewModel.areNotificationsVisible.collectAsState() + lockscreenContentViewModel.areNotificationsVisible.collectAsStateWithLifecycle() val splitShadeTopMargin: Dp = if (Flags.centralizedStatusBarHeightFix()) { LargeScreenHeaderHelper.getLargeScreenHeaderHeight(LocalContext.current).dp @@ -103,6 +106,7 @@ constructor( } ConstrainedNotificationStack( + stackScrollView = stackScrollView.get(), viewModel = viewModel, modifier = modifier diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt index fc8b3b9009ce..44bda956b9f6 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/SmartSpaceSection.kt @@ -26,7 +26,6 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -34,6 +33,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.compose.modifiers.padding import com.android.systemui.keyguard.KeyguardUnlockAnimationController @@ -160,7 +160,7 @@ constructor( private fun Weather( modifier: Modifier = Modifier, ) { - val isVisible by keyguardSmartspaceViewModel.isWeatherVisible.collectAsState() + val isVisible by keyguardSmartspaceViewModel.isWeatherVisible.collectAsStateWithLifecycle() if (!isVisible) { return } @@ -187,7 +187,7 @@ constructor( private fun Date( modifier: Modifier = Modifier, ) { - val isVisible by keyguardSmartspaceViewModel.isDateVisible.collectAsState() + val isVisible by keyguardSmartspaceViewModel.isDateVisible.collectAsStateWithLifecycle() if (!isVisible) { return } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt index 63c70c97ed07..88b8298335aa 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/section/TopAreaSection.kt @@ -25,7 +25,6 @@ import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.wrapContentSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -33,6 +32,7 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.SceneTransitionLayout import com.android.compose.modifiers.thenIf @@ -62,9 +62,9 @@ constructor( fun DefaultClockLayout( modifier: Modifier = Modifier, ) { - val currentClockLayout by clockViewModel.currentClockLayout.collectAsState() + val currentClockLayout by clockViewModel.currentClockLayout.collectAsStateWithLifecycle() val hasCustomPositionUpdatedAnimation by - clockViewModel.hasCustomPositionUpdatedAnimation.collectAsState() + clockViewModel.hasCustomPositionUpdatedAnimation.collectAsStateWithLifecycle() val currentScene = when (currentClockLayout) { KeyguardClockViewModel.ClockLayout.SPLIT_SHADE_LARGE_CLOCK -> @@ -133,7 +133,7 @@ constructor( @Composable private fun SceneScope.LargeClockWithSmartSpace(shouldOffSetClockToOneHalf: Boolean = false) { val burnIn = rememberBurnIn(clockInteractor) - val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsState() + val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsStateWithLifecycle() LaunchedEffect(isLargeClockVisible) { if (isLargeClockVisible) { @@ -170,8 +170,8 @@ constructor( @Composable private fun SceneScope.WeatherLargeClockWithSmartSpace(modifier: Modifier = Modifier) { val burnIn = rememberBurnIn(clockInteractor) - val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsState() - val currentClockState = clockViewModel.currentClock.collectAsState() + val isLargeClockVisible by clockViewModel.isLargeClockVisible.collectAsStateWithLifecycle() + val currentClockState = clockViewModel.currentClock.collectAsStateWithLifecycle() LaunchedEffect(isLargeClockVisible) { if (isLargeClockVisible) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt index 241c171f7862..581f3a5cacff 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/media/controls/ui/composable/MediaCarousel.kt @@ -42,12 +42,12 @@ private object MediaCarousel { @Composable fun SceneScope.MediaCarousel( - isVisible: () -> Boolean, + isVisible: Boolean, mediaHost: MediaHost, modifier: Modifier = Modifier, carouselController: MediaCarouselController, ) { - if (!isVisible()) { + if (!isVisible) { return } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackContentHeight.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackContentHeight.kt new file mode 100644 index 000000000000..9f829cccfb32 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationStackContentHeight.kt @@ -0,0 +1,93 @@ +/* + * 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.composable + +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.Measurable +import androidx.compose.ui.layout.MeasureResult +import androidx.compose.ui.layout.MeasureScope +import androidx.compose.ui.node.LayoutModifierNode +import androidx.compose.ui.node.ModifierNodeElement +import androidx.compose.ui.node.invalidateMeasurement +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.IntOffset +import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView + +/** + * Modify element, which updates the height to be the same as the Notification stack height returned + * by the legacy Notification stack scroll view in [NotificationScrollView.intrinsicStackHeight]. + * + * @param view Notification stack scroll view + * @param padding extra padding in pixels to be added to the received content height. + */ +fun Modifier.notificationStackHeight(view: NotificationScrollView, padding: Int = 0) = + this then StackLayoutElement(view, padding) + +private data class StackLayoutElement( + val view: NotificationScrollView, + val padding: Int, +) : ModifierNodeElement<StackLayoutNode>() { + + override fun create(): StackLayoutNode = StackLayoutNode(view, padding) + + override fun update(node: StackLayoutNode) { + check(view == node.view) { "Trying to reuse the node with a new View." } + if (node.padding != padding) { + node.padding = padding + node.invalidateMeasureIfAttached() + } + } +} + +private class StackLayoutNode(val view: NotificationScrollView, var padding: Int) : + LayoutModifierNode, Modifier.Node() { + + private val stackHeightChangedListener = Runnable { invalidateMeasureIfAttached() } + + override fun onAttach() { + super.onAttach() + view.addStackHeightChangedListener(stackHeightChangedListener) + } + + override fun onDetach() { + super.onDetach() + view.removeStackHeightChangedListener(stackHeightChangedListener) + } + + override fun MeasureScope.measure( + measurable: Measurable, + constraints: Constraints + ): MeasureResult { + val contentHeight = padding + view.intrinsicStackHeight + val placeable = + measurable.measure( + constraints.copy(minHeight = contentHeight, maxHeight = contentHeight) + ) + + return layout(placeable.width, placeable.height) { placeable.place(IntOffset.Zero) } + } + + override fun toString(): String { + return "StackLayoutNode(view=$view padding:$padding)" + } + + fun invalidateMeasureIfAttached() { + if (isAttached) { + this.invalidateMeasurement() + } + } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt index 3ce0feb0af56..cf2e895b044b 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt @@ -38,8 +38,9 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment @@ -62,19 +63,23 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.compose.ui.util.lerp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.NestedScrollBehavior import com.android.compose.animation.scene.SceneScope import com.android.compose.modifiers.height +import com.android.compose.modifiers.thenIf import com.android.systemui.common.ui.compose.windowinsets.LocalRawScreenHeight import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.session.ui.composable.rememberSession import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.composable.ShadeHeader import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimRounding +import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationTransitionThresholds.EXPANSION_FOR_MAX_CORNER_RADIUS import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationTransitionThresholds.EXPANSION_FOR_MAX_SCRIM_ALPHA import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel @@ -107,7 +112,7 @@ fun SceneScope.HeadsUpNotificationSpace( modifier: Modifier = Modifier, isPeekFromBottom: Boolean = false, ) { - val headsUpHeight = viewModel.headsUpHeight.collectAsState() + val headsUpHeight = viewModel.headsUpHeight.collectAsStateWithLifecycle() Element( Notifications.Elements.HeadsUpNotificationPlaceholder, @@ -133,6 +138,7 @@ fun SceneScope.HeadsUpNotificationSpace( /** Adds the space where notification stack should appear in the scene. */ @Composable fun SceneScope.ConstrainedNotificationStack( + stackScrollView: NotificationScrollView, viewModel: NotificationsPlaceholderViewModel, modifier: Modifier = Modifier, ) { @@ -141,6 +147,7 @@ fun SceneScope.ConstrainedNotificationStack( modifier.onSizeChanged { viewModel.onConstrainedAvailableSpaceChanged(it.height) } ) { NotificationPlaceholder( + stackScrollView = stackScrollView, viewModel = viewModel, modifier = Modifier.fillMaxSize(), ) @@ -158,9 +165,11 @@ fun SceneScope.ConstrainedNotificationStack( @Composable fun SceneScope.NotificationScrollingStack( shadeSession: SaveableSession, + stackScrollView: NotificationScrollView, viewModel: NotificationsPlaceholderViewModel, maxScrimTop: () -> Float, shouldPunchHoleBehindScrim: Boolean, + shadeMode: ShadeMode, modifier: Modifier = Modifier, ) { val coroutineScope = rememberCoroutineScope() @@ -171,17 +180,24 @@ fun SceneScope.NotificationScrollingStack( shadeSession.rememberSaveableSession(saver = ScrollState.Saver, key = null) { ScrollState(initial = 0) } - val syntheticScroll = viewModel.syntheticScroll.collectAsState(0f) - val isCurrentGestureOverscroll = viewModel.isCurrentGestureOverscroll.collectAsState(false) - val expansionFraction by viewModel.expandFraction.collectAsState(0f) + val syntheticScroll = viewModel.syntheticScroll.collectAsStateWithLifecycle(0f) + val isCurrentGestureOverscroll = + viewModel.isCurrentGestureOverscroll.collectAsStateWithLifecycle(false) + val expansionFraction by viewModel.expandFraction.collectAsStateWithLifecycle(0f) val navBarHeight = with(density) { WindowInsets.systemBars.asPaddingValues().calculateBottomPadding().toPx() } val screenHeight = LocalRawScreenHeight.current - val stackHeight = viewModel.stackHeight.collectAsState() + /** + * The height in px of the contents of notification stack. Depending on the number of + * notifications, this can exceed the space available on screen to show notifications, at which + * point the notification stack should become scrollable. + */ + val stackHeight = remember { mutableIntStateOf(0) } - val scrimRounding = viewModel.shadeScrimRounding.collectAsState(ShadeScrimRounding()) + val scrimRounding = + viewModel.shadeScrimRounding.collectAsStateWithLifecycle(ShadeScrimRounding()) // the offset for the notifications scrim. Its upper bound is 0, and its lower bound is // calculated in minScrimOffset. The scrim is the same height as the screen minus the @@ -212,7 +228,7 @@ fun SceneScope.NotificationScrollingStack( // if contentHeight drops below minimum visible scrim height while scrim is // expanded, reset scrim offset. LaunchedEffect(stackHeight, scrimOffset) { - snapshotFlow { stackHeight.value < minVisibleScrimHeight() && scrimOffset.value < 0f } + snapshotFlow { stackHeight.intValue < minVisibleScrimHeight() && scrimOffset.value < 0f } .collect { shouldCollapse -> if (shouldCollapse) scrimOffset.snapTo(0f) } } @@ -233,6 +249,27 @@ fun SceneScope.NotificationScrollingStack( } } + val scrimNestedScrollConnection = + shadeSession.rememberSession( + scrimOffset, + maxScrimTop, + minScrimTop, + isCurrentGestureOverscroll, + ) { + NotificationScrimNestedScrollConnection( + scrimOffset = { scrimOffset.value }, + snapScrimOffset = { value -> coroutineScope.launch { scrimOffset.snapTo(value) } }, + animateScrimOffset = { value -> + coroutineScope.launch { scrimOffset.animateTo(value) } + }, + minScrimOffset = minScrimOffset, + maxScrimOffset = 0f, + contentHeight = { stackHeight.intValue.toFloat() }, + minVisibleScrimHeight = minVisibleScrimHeight, + isCurrentGestureOverscroll = { isCurrentGestureOverscroll.value }, + ) + } + Box( modifier = modifier @@ -301,40 +338,23 @@ fun SceneScope.NotificationScrollingStack( .debugBackground(viewModel, DEBUG_BOX_COLOR) ) { NotificationPlaceholder( + stackScrollView = stackScrollView, viewModel = viewModel, modifier = Modifier.verticalNestedScrollToScene( topBehavior = NestedScrollBehavior.EdgeWithPreview, isExternalOverscrollGesture = { isCurrentGestureOverscroll.value } ) - .nestedScroll( - shadeSession.rememberSession( - scrimOffset, - maxScrimTop, - minScrimTop, - isCurrentGestureOverscroll, - ) { - NotificationScrimNestedScrollConnection( - scrimOffset = { scrimOffset.value }, - snapScrimOffset = { value -> - coroutineScope.launch { scrimOffset.snapTo(value) } - }, - animateScrimOffset = { value -> - coroutineScope.launch { scrimOffset.animateTo(value) } - }, - minScrimOffset = minScrimOffset, - maxScrimOffset = 0f, - contentHeight = { stackHeight.value }, - minVisibleScrimHeight = minVisibleScrimHeight, - isCurrentGestureOverscroll = { - isCurrentGestureOverscroll.value - }, - ) - } - ) + .thenIf(shadeMode == ShadeMode.Single) { + Modifier.nestedScroll(scrimNestedScrollConnection) + } .verticalScroll(scrollState) .fillMaxWidth() - .height { (stackHeight.value + navBarHeight).roundToInt() }, + .notificationStackHeight( + view = stackScrollView, + padding = navBarHeight.toInt() + ) + .onSizeChanged { size -> stackHeight.intValue = size.height }, ) } HeadsUpNotificationSpace(viewModel = viewModel) @@ -375,6 +395,7 @@ fun SceneScope.NotificationShelfSpace( @Composable private fun SceneScope.NotificationPlaceholder( + stackScrollView: NotificationScrollView, viewModel: NotificationsPlaceholderViewModel, modifier: Modifier = Modifier, ) { @@ -393,10 +414,8 @@ private fun SceneScope.NotificationPlaceholder( " bounds=${coordinates.boundsInWindow()}" } // NOTE: positionInWindow.y scrolls off screen, but boundsInWindow.top will not - viewModel.onStackBoundsChanged( - top = positionInWindow.y, - bottom = positionInWindow.y + coordinates.size.height, - ) + stackScrollView.setStackTop(positionInWindow.y) + stackScrollView.setStackBottom(positionInWindow.y + coordinates.size.height) } ) { content {} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt index 73cb72ca062e..b808044b76ce 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/people/ui/compose/PeopleScreen.kt @@ -36,7 +36,6 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.ui.Alignment @@ -46,6 +45,7 @@ import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.theme.LocalAndroidColorScheme import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.people.ui.viewmodel.PeopleTileViewModel @@ -64,8 +64,8 @@ fun PeopleScreen( viewModel: PeopleViewModel, onResult: (PeopleViewModel.Result) -> Unit, ) { - val priorityTiles by viewModel.priorityTiles.collectAsState() - val recentTiles by viewModel.recentTiles.collectAsState() + val priorityTiles by viewModel.priorityTiles.collectAsStateWithLifecycle() + val recentTiles by viewModel.recentTiles.collectAsStateWithLifecycle() // Call [onResult] this activity when the ViewModel tells us so. LaunchedEffect(viewModel.result) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt index 5f84dd47a240..e8da4bd2d2cd 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/FooterActions.kt @@ -44,7 +44,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -69,6 +68,7 @@ import androidx.compose.ui.unit.em import androidx.compose.ui.unit.sp import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.compose.animation.Expandable import com.android.compose.animation.scene.SceneScope @@ -132,8 +132,8 @@ fun FooterActions( val context = LocalContext.current // Collect alphas as soon as we are composed, even when not visible. - val alpha by viewModel.alpha.collectAsState() - val backgroundAlpha = viewModel.backgroundAlpha.collectAsState() + val alpha by viewModel.alpha.collectAsStateWithLifecycle() + val backgroundAlpha = viewModel.backgroundAlpha.collectAsStateWithLifecycle() var security by remember { mutableStateOf<FooterActionsSecurityButtonViewModel?>(null) } var foregroundServices by remember { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt index ca6b3434d90e..73a624a030fe 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/BrightnessMirror.kt @@ -21,13 +21,13 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.offset import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.viewinterop.AndroidView +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.modifiers.height import com.android.compose.modifiers.width import com.android.systemui.qs.ui.adapter.QSSceneAdapter @@ -40,13 +40,13 @@ fun BrightnessMirror( qsSceneAdapter: QSSceneAdapter, modifier: Modifier = Modifier, ) { - val isShowing by viewModel.isShowing.collectAsState() + val isShowing by viewModel.isShowing.collectAsStateWithLifecycle() val mirrorAlpha by animateFloatAsState( targetValue = if (isShowing) 1f else 0f, label = "alphaAnimationBrightnessMirrorShowing", ) - val mirrorOffsetAndSize by viewModel.locationAndSize.collectAsState() + val mirrorOffsetAndSize by viewModel.locationAndSize.collectAsStateWithLifecycle() val offset = IntOffset(0, mirrorOffsetAndSize.yOffset) Box(modifier = modifier.fillMaxSize().graphicsLayer { alpha = mirrorAlpha }) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt index 46be6b898b8d..d1099883c5e5 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt @@ -22,18 +22,19 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.layout.layout import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.viewinterop.AndroidView +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.MovableElementScenePicker import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.TransitionState import com.android.compose.animation.scene.ValueKey import com.android.compose.modifiers.thenIf +import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Companion.Collapsing import com.android.systemui.qs.ui.adapter.QSSceneAdapter.State.Expanding @@ -143,7 +144,9 @@ fun SceneScope.QuickSettings( MovableElement( key = QuickSettings.Elements.Content, modifier = - modifier.fillMaxWidth().layout { measurable, constraints -> + modifier.sysuiResTag("quick_settings_panel").fillMaxWidth().layout { + measurable, + constraints -> val placeable = measurable.measure(constraints) // Use the height of the correct view based on the scene it is being composed in val height = heightProvider().coerceAtLeast(0) @@ -161,9 +164,11 @@ private fun QuickSettingsContent( state: QSSceneAdapter.State, modifier: Modifier = Modifier, ) { - val qsView by qsSceneAdapter.qsView.collectAsState(null) + val qsView by qsSceneAdapter.qsView.collectAsStateWithLifecycle(null) val isCustomizing by - qsSceneAdapter.isCustomizerShowing.collectAsState(qsSceneAdapter.isCustomizerShowing.value) + qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle( + qsSceneAdapter.isCustomizerShowing.value + ) QuickSettingsTheme { val context = LocalContext.current diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt index 30b6c6cb4c4f..d76b19f3fa82 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt @@ -51,7 +51,6 @@ import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.ui.Alignment @@ -63,6 +62,7 @@ import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.colorResource import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.SceneScope import com.android.compose.animation.scene.TransitionState import com.android.compose.animation.scene.animateSceneFloatAsState @@ -86,14 +86,17 @@ import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.ComposableScene +import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.composable.CollapsedShadeHeader import com.android.systemui.shade.ui.composable.ExpandedShadeHeader import com.android.systemui.shade.ui.composable.Shade import com.android.systemui.shade.ui.composable.ShadeHeader +import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.phone.ui.StatusBarIconController import com.android.systemui.statusbar.phone.ui.TintedIconManager +import dagger.Lazy import javax.inject.Inject import javax.inject.Named import kotlin.math.roundToInt @@ -108,6 +111,7 @@ class QuickSettingsScene constructor( @Application private val applicationScope: CoroutineScope, private val shadeSession: SaveableSession, + private val notificationStackScrollView: Lazy<NotificationScrollView>, private val viewModel: QuickSettingsSceneViewModel, private val notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel, private val tintedIconManagerFactory: TintedIconManager.Factory, @@ -130,6 +134,7 @@ constructor( modifier: Modifier, ) { QuickSettingsScene( + notificationStackScrollView = notificationStackScrollView.get(), viewModel = viewModel, notificationsPlaceholderViewModel = notificationsPlaceholderViewModel, createTintedIconManager = tintedIconManagerFactory::create, @@ -145,6 +150,7 @@ constructor( @Composable private fun SceneScope.QuickSettingsScene( + notificationStackScrollView: NotificationScrollView, viewModel: QuickSettingsSceneViewModel, notificationsPlaceholderViewModel: NotificationsPlaceholderViewModel, createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager, @@ -157,7 +163,8 @@ private fun SceneScope.QuickSettingsScene( ) { val cutoutLocation = LocalDisplayCutout.current.location - val brightnessMirrorShowing by viewModel.brightnessMirrorViewModel.isShowing.collectAsState() + val brightnessMirrorShowing by + viewModel.brightnessMirrorViewModel.isShowing.collectAsStateWithLifecycle() val contentAlpha by animateFloatAsState( targetValue = if (brightnessMirrorShowing) 0f else 1f, @@ -192,10 +199,11 @@ private fun SceneScope.QuickSettingsScene( Modifier.displayCutoutPadding() }, ) { - val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState() - val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsState() + val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle() + val isCustomizerShowing by + viewModel.qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle() val customizingAnimationDuration by - viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsState() + viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsStateWithLifecycle() val screenHeight = LocalRawScreenHeight.current BackHandler( @@ -288,7 +296,8 @@ private fun SceneScope.QuickSettingsScene( } Column( - modifier = shadeHeaderAndQuickSettingsModifier, + modifier = + shadeHeaderAndQuickSettingsModifier.sysuiResTag("expanded_qs_scroll_view"), ) { when (LocalWindowSizeClass.current.widthSizeClass) { WindowWidthSizeClass.Compact -> @@ -336,11 +345,13 @@ private fun SceneScope.QuickSettingsScene( viewModel.qsSceneAdapter, { viewModel.qsSceneAdapter.qsHeight }, isSplitShade = false, - modifier = Modifier.sysuiResTag("expanded_qs_scroll_view") + modifier = Modifier ) + val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle() + MediaCarousel( - isVisible = viewModel::isMediaVisible, + isVisible = isMediaVisible, mediaHost = mediaHost, modifier = Modifier.fillMaxWidth(), carouselController = mediaCarouselController, @@ -353,14 +364,17 @@ private fun SceneScope.QuickSettingsScene( isCustomizing = isCustomizing, customizingAnimationDuration = customizingAnimationDuration, lifecycleOwner = lifecycleOwner, - modifier = Modifier.align(Alignment.CenterHorizontally), + modifier = + Modifier.align(Alignment.CenterHorizontally).sysuiResTag("qs_footer_actions"), ) } NotificationScrollingStack( + stackScrollView = notificationStackScrollView, viewModel = notificationsPlaceholderViewModel, shadeSession = shadeSession, maxScrimTop = { screenHeight }, shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim, + shadeMode = ShadeMode.Single, modifier = Modifier.fillMaxWidth().offset { IntOffset(x = 0, y = screenHeight.roundToInt()) }, ) 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 7af9b7bb90e9..92b2b4e886b9 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 @@ -23,7 +23,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -34,6 +33,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.PointerEventPass import androidx.compose.ui.input.pointer.motionEventSpy import androidx.compose.ui.input.pointer.pointerInput +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.MutableSceneTransitionLayoutState import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.SceneTransitionLayout @@ -68,8 +68,9 @@ fun SceneContainer( modifier: Modifier = Modifier, ) { val coroutineScope = rememberCoroutineScope() - val currentSceneKey: SceneKey by viewModel.currentScene.collectAsState() - val currentDestinations by viewModel.currentDestinationScenes(coroutineScope).collectAsState() + val currentSceneKey: SceneKey by viewModel.currentScene.collectAsStateWithLifecycle() + val currentDestinations by + viewModel.currentDestinationScenes(coroutineScope).collectAsStateWithLifecycle() val state: MutableSceneTransitionLayoutState = remember { MutableSceneTransitionLayoutState( initialScene = currentSceneKey, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt index ff9c5a5ee586..cbaa89438f2e 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt @@ -5,9 +5,8 @@ import com.android.compose.animation.scene.transitions import com.android.systemui.bouncer.ui.composable.Bouncer import com.android.systemui.notifications.ui.composable.Notifications import com.android.systemui.scene.shared.model.Scenes -import com.android.systemui.scene.shared.model.TransitionKeys.CollapseShadeInstantly -import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse +import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade import com.android.systemui.scene.ui.composable.transitions.bouncerToGoneTransition import com.android.systemui.scene.ui.composable.transitions.goneToQuickSettingsTransition import com.android.systemui.scene.ui.composable.transitions.goneToShadeTransition @@ -17,6 +16,7 @@ import com.android.systemui.scene.ui.composable.transitions.lockscreenToCommunal import com.android.systemui.scene.ui.composable.transitions.lockscreenToGoneTransition import com.android.systemui.scene.ui.composable.transitions.lockscreenToQuickSettingsTransition import com.android.systemui.scene.ui.composable.transitions.lockscreenToShadeTransition +import com.android.systemui.scene.ui.composable.transitions.lockscreenToSplitShadeTransition import com.android.systemui.scene.ui.composable.transitions.shadeToQuickSettingsTransition import com.android.systemui.shade.ui.composable.Shade @@ -41,7 +41,7 @@ val SceneContainerTransitions = transitions { from( Scenes.Gone, to = Scenes.Shade, - key = GoneToSplitShade, + key = ToSplitShade, ) { goneToSplitShadeTransition() } @@ -59,6 +59,13 @@ val SceneContainerTransitions = transitions { from( Scenes.Lockscreen, to = Scenes.Shade, + key = ToSplitShade, + ) { + lockscreenToSplitShadeTransition() + } + from( + Scenes.Lockscreen, + to = Scenes.Shade, key = SlightlyFasterShadeCollapse, ) { lockscreenToShadeTransition(durationScale = 0.9) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt index 4dc36d6f1878..f14ff76df5db 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToSplitShadeTransition.kt @@ -16,50 +16,10 @@ package com.android.systemui.scene.ui.composable.transitions -import androidx.compose.animation.core.Spring -import androidx.compose.animation.core.spring -import androidx.compose.animation.core.tween -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.ui.unit.IntSize import com.android.compose.animation.scene.TransitionBuilder -import com.android.compose.animation.scene.UserActionDistance -import com.android.compose.animation.scene.UserActionDistanceScope -import com.android.systemui.notifications.ui.composable.Notifications -import com.android.systemui.qs.ui.composable.QuickSettings -import com.android.systemui.shade.ui.composable.Shade -import com.android.systemui.shade.ui.composable.ShadeHeader -import kotlin.time.Duration.Companion.milliseconds fun TransitionBuilder.goneToSplitShadeTransition( durationScale: Double = 1.0, ) { - spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt()) - swipeSpec = - spring( - stiffness = Spring.StiffnessMediumLow, - visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold, - ) - distance = - object : UserActionDistance { - override fun UserActionDistanceScope.absoluteDistance( - fromSceneSize: IntSize, - orientation: Orientation, - ): Float { - return fromSceneSize.height.toFloat() * 2 / 3f - } - } - - fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) } - - fractionRange(start = .33f) { - fade(ShadeHeader.Elements.Clock) - fade(ShadeHeader.Elements.CollapsedContentStart) - fade(ShadeHeader.Elements.CollapsedContentEnd) - fade(ShadeHeader.Elements.PrivacyChip) - fade(QuickSettings.Elements.SplitShadeQuickSettings) - fade(QuickSettings.Elements.FooterActions) - fade(Notifications.Elements.NotificationScrim) - } + toSplitShadeTransition(durationScale) } - -private val DefaultDuration = 500.milliseconds diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt new file mode 100644 index 000000000000..70c343ceacda --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToSplitShadeTransition.kt @@ -0,0 +1,25 @@ +/* + * 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.scene.ui.composable.transitions + +import com.android.compose.animation.scene.TransitionBuilder + +fun TransitionBuilder.lockscreenToSplitShadeTransition( + durationScale: Double = 1.0, +) { + toSplitShadeTransition(durationScale = durationScale) +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToSplitShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToSplitShadeTransition.kt new file mode 100644 index 000000000000..a8315c05c7d1 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToSplitShadeTransition.kt @@ -0,0 +1,65 @@ +/* + * 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.scene.ui.composable.transitions + +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring +import androidx.compose.animation.core.tween +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.ui.unit.IntSize +import com.android.compose.animation.scene.TransitionBuilder +import com.android.compose.animation.scene.UserActionDistance +import com.android.compose.animation.scene.UserActionDistanceScope +import com.android.systemui.notifications.ui.composable.Notifications +import com.android.systemui.qs.ui.composable.QuickSettings +import com.android.systemui.shade.ui.composable.Shade +import com.android.systemui.shade.ui.composable.ShadeHeader +import kotlin.time.Duration.Companion.milliseconds + +fun TransitionBuilder.toSplitShadeTransition( + durationScale: Double = 1.0, +) { + spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt()) + swipeSpec = + spring( + stiffness = Spring.StiffnessMediumLow, + visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold, + ) + distance = + object : UserActionDistance { + override fun UserActionDistanceScope.absoluteDistance( + fromSceneSize: IntSize, + orientation: Orientation, + ): Float { + return fromSceneSize.height.toFloat() * 2 / 3f + } + } + + fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) } + + fractionRange(start = .33f) { + fade(ShadeHeader.Elements.Clock) + fade(ShadeHeader.Elements.CollapsedContentStart) + fade(ShadeHeader.Elements.CollapsedContentEnd) + fade(ShadeHeader.Elements.PrivacyChip) + fade(QuickSettings.Elements.SplitShadeQuickSettings) + fade(QuickSettings.Elements.FooterActions) + fade(Notifications.Elements.NotificationScrim) + } +} + +private val DefaultDuration = 500.milliseconds 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 d5287362c36d..00ef11d3b745 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 @@ -30,13 +30,13 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.ReadOnlyComposable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue 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.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.LowestZIndexScenePicker import com.android.compose.animation.scene.SceneScope @@ -51,7 +51,7 @@ fun SceneScope.OverlayShade( modifier: Modifier = Modifier, content: @Composable () -> Unit, ) { - val backgroundScene by viewModel.backgroundScene.collectAsState() + val backgroundScene by viewModel.backgroundScene.collectAsStateWithLifecycle() Box(modifier) { if (backgroundScene == Scenes.Lockscreen) { 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 709a416c0366..ac3e015e52a9 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 @@ -35,7 +35,6 @@ import androidx.compose.foundation.layout.widthIn import androidx.compose.material3.ColorScheme import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember @@ -52,6 +51,7 @@ import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.max import androidx.compose.ui.viewinterop.AndroidView +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.LowestZIndexScenePicker import com.android.compose.animation.scene.SceneScope @@ -118,7 +118,7 @@ fun SceneScope.CollapsedShadeHeader( statusBarIconController: StatusBarIconController, modifier: Modifier = Modifier, ) { - val isDisabled by viewModel.isDisabled.collectAsState() + val isDisabled by viewModel.isDisabled.collectAsStateWithLifecycle() if (isDisabled) { return } @@ -138,7 +138,7 @@ fun SceneScope.CollapsedShadeHeader( } } - val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsState() + val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle() // This layout assumes it is globally positioned at (0, 0) and is the // same size as the screen. @@ -271,7 +271,7 @@ fun SceneScope.ExpandedShadeHeader( statusBarIconController: StatusBarIconController, modifier: Modifier = Modifier, ) { - val isDisabled by viewModel.isDisabled.collectAsState() + val isDisabled by viewModel.isDisabled.collectAsStateWithLifecycle() if (isDisabled) { return } @@ -280,7 +280,7 @@ fun SceneScope.ExpandedShadeHeader( derivedStateOf { shouldUseExpandedFormat(layoutState.transitionState) } } - val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsState() + val isPrivacyChipVisible by viewModel.isPrivacyChipVisible.collectAsStateWithLifecycle() Box(modifier = modifier.sysuiResTag(ShadeHeader.TestTags.Root)) { if (isPrivacyChipVisible) { @@ -435,7 +435,7 @@ private fun ShadeCarrierGroup( modifier: Modifier = Modifier, ) { Row(modifier = modifier) { - val subIds by viewModel.mobileSubIds.collectAsState() + val subIds by viewModel.mobileSubIds.collectAsStateWithLifecycle() for (subId in subIds) { Spacer(modifier = Modifier.width(5.dp)) @@ -472,10 +472,12 @@ private fun SceneScope.StatusIcons( val micSlot = stringResource(id = com.android.internal.R.string.status_bar_microphone) val locationSlot = stringResource(id = com.android.internal.R.string.status_bar_location) - val isSingleCarrier by viewModel.isSingleCarrier.collectAsState() - val isPrivacyChipEnabled by viewModel.isPrivacyChipEnabled.collectAsState() - val isMicCameraIndicationEnabled by viewModel.isMicCameraIndicationEnabled.collectAsState() - val isLocationIndicationEnabled by viewModel.isLocationIndicationEnabled.collectAsState() + val isSingleCarrier by viewModel.isSingleCarrier.collectAsStateWithLifecycle() + val isPrivacyChipEnabled by viewModel.isPrivacyChipEnabled.collectAsStateWithLifecycle() + val isMicCameraIndicationEnabled by + viewModel.isMicCameraIndicationEnabled.collectAsStateWithLifecycle() + val isLocationIndicationEnabled by + viewModel.isLocationIndicationEnabled.collectAsStateWithLifecycle() AndroidView( factory = { context -> @@ -544,7 +546,7 @@ private fun SceneScope.PrivacyChip( viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier, ) { - val privacyList by viewModel.privacyItems.collectAsState() + val privacyList by viewModel.privacyItems.collectAsStateWithLifecycle() AndroidView( factory = { context -> diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt index 10fe0cabad53..a0278a616857 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt @@ -45,7 +45,6 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -58,6 +57,7 @@ import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.colorResource import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.LowestZIndexScenePicker import com.android.compose.animation.scene.SceneScope @@ -71,6 +71,7 @@ import com.android.systemui.battery.BatteryMeterViewController import com.android.systemui.common.ui.compose.windowinsets.CutoutLocation import com.android.systemui.common.ui.compose.windowinsets.LocalDisplayCutout import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius +import com.android.systemui.compose.modifiers.sysuiResTag import com.android.systemui.dagger.SysUISingleton import com.android.systemui.media.controls.ui.composable.MediaCarousel import com.android.systemui.media.controls.ui.controller.MediaCarouselController @@ -88,9 +89,11 @@ import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.ComposableScene import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.viewmodel.ShadeSceneViewModel +import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView import com.android.systemui.statusbar.phone.StatusBarLocation import com.android.systemui.statusbar.phone.ui.StatusBarIconController import com.android.systemui.statusbar.phone.ui.TintedIconManager +import dagger.Lazy import javax.inject.Inject import javax.inject.Named import kotlin.math.roundToInt @@ -126,6 +129,7 @@ class ShadeScene @Inject constructor( private val shadeSession: SaveableSession, + private val notificationStackScrollView: Lazy<NotificationScrollView>, private val viewModel: ShadeSceneViewModel, private val tintedIconManagerFactory: TintedIconManager.Factory, private val batteryMeterViewControllerFactory: BatteryMeterViewController.Factory, @@ -144,6 +148,7 @@ constructor( modifier: Modifier, ) = ShadeScene( + notificationStackScrollView.get(), viewModel = viewModel, createTintedIconManager = tintedIconManagerFactory::create, createBatteryMeterViewController = batteryMeterViewControllerFactory::create, @@ -163,6 +168,7 @@ constructor( @Composable private fun SceneScope.ShadeScene( + notificationStackScrollView: NotificationScrollView, viewModel: ShadeSceneViewModel, createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager, createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController, @@ -172,10 +178,11 @@ private fun SceneScope.ShadeScene( modifier: Modifier = Modifier, shadeSession: SaveableSession, ) { - val shadeMode by viewModel.shadeMode.collectAsState() + val shadeMode by viewModel.shadeMode.collectAsStateWithLifecycle() when (shadeMode) { is ShadeMode.Single -> SingleShade( + notificationStackScrollView = notificationStackScrollView, viewModel = viewModel, createTintedIconManager = createTintedIconManager, createBatteryMeterViewController = createBatteryMeterViewController, @@ -187,6 +194,7 @@ private fun SceneScope.ShadeScene( ) is ShadeMode.Split -> SplitShade( + notificationStackScrollView = notificationStackScrollView, viewModel = viewModel, createTintedIconManager = createTintedIconManager, createBatteryMeterViewController = createBatteryMeterViewController, @@ -202,6 +210,7 @@ private fun SceneScope.ShadeScene( @Composable private fun SceneScope.SingleShade( + notificationStackScrollView: NotificationScrollView, viewModel: ShadeSceneViewModel, createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager, createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController, @@ -220,7 +229,8 @@ private fun SceneScope.SingleShade( key = QuickSettings.SharedValues.TilesSquishiness, canOverflow = false ) - val isClickable by viewModel.isClickable.collectAsState() + val isClickable by viewModel.isClickable.collectAsStateWithLifecycle() + val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle() val shouldPunchHoleBehindScrim = layoutState.isTransitioningBetween(Scenes.Gone, Scenes.Shade) || @@ -274,7 +284,7 @@ private fun SceneScope.SingleShade( } MediaCarousel( - isVisible = viewModel::isMediaVisible, + isVisible = isMediaVisible, mediaHost = mediaHost, modifier = Modifier.fillMaxWidth(), carouselController = mediaCarouselController, @@ -286,8 +296,10 @@ private fun SceneScope.SingleShade( { NotificationScrollingStack( shadeSession = shadeSession, + stackScrollView = notificationStackScrollView, viewModel = viewModel.notifications, maxScrimTop = { maxNotifScrimTop.value }, + shadeMode = ShadeMode.Single, shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim, ) }, @@ -312,6 +324,7 @@ private fun SceneScope.SingleShade( @Composable private fun SceneScope.SplitShade( + notificationStackScrollView: NotificationScrollView, viewModel: ShadeSceneViewModel, createTintedIconManager: (ViewGroup, StatusBarLocation) -> TintedIconManager, createBatteryMeterViewController: (ViewGroup, StatusBarLocation) -> BatteryMeterViewController, @@ -323,10 +336,11 @@ private fun SceneScope.SplitShade( ) { val screenCornerRadius = LocalScreenCornerRadius.current - val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState() - val isCustomizerShowing by viewModel.qsSceneAdapter.isCustomizerShowing.collectAsState() + val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsStateWithLifecycle() + val isCustomizerShowing by + viewModel.qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle() val customizingAnimationDuration by - viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsState() + viewModel.qsSceneAdapter.customizerAnimationDuration.collectAsStateWithLifecycle() val lifecycleOwner = LocalLifecycleOwner.current val footerActionsViewModel = remember(lifecycleOwner, viewModel) { viewModel.getFooterActionsViewModel(lifecycleOwner) } @@ -341,13 +355,13 @@ private fun SceneScope.SplitShade( .unfoldTranslationX( isOnStartSide = true, ) - .collectAsState(0f) + .collectAsStateWithLifecycle(0f) val unfoldTranslationXForEndSide by viewModel .unfoldTranslationX( isOnStartSide = false, ) - .collectAsState(0f) + .collectAsStateWithLifecycle(0f) val navBarBottomHeight = WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding() val bottomPadding by @@ -371,7 +385,8 @@ private fun SceneScope.SplitShade( } } - val brightnessMirrorShowing by viewModel.brightnessMirrorViewModel.isShowing.collectAsState() + val brightnessMirrorShowing by + viewModel.brightnessMirrorViewModel.isShowing.collectAsStateWithLifecycle() val contentAlpha by animateFloatAsState( targetValue = if (brightnessMirrorShowing) 0f else 1f, @@ -381,6 +396,8 @@ private fun SceneScope.SplitShade( viewModel.notifications.setAlphaForBrightnessMirror(contentAlpha) DisposableEffect(Unit) { onDispose { viewModel.notifications.setAlphaForBrightnessMirror(1f) } } + val isMediaVisible by viewModel.isMediaVisible.collectAsStateWithLifecycle() + val brightnessMirrorShowingModifier = Modifier.graphicsLayer { alpha = contentAlpha } Box( @@ -430,6 +447,7 @@ private fun SceneScope.SplitShade( Column( modifier = Modifier.fillMaxSize() + .sysuiResTag("expanded_qs_scroll_view") .weight(1f) .thenIf(!isCustomizerShowing) { Modifier.verticalNestedScrollToScene() @@ -455,7 +473,7 @@ private fun SceneScope.SplitShade( } MediaCarousel( - isVisible = viewModel::isMediaVisible, + isVisible = isMediaVisible, mediaHost = mediaHost, modifier = Modifier.fillMaxWidth(), carouselController = mediaCarouselController, @@ -468,6 +486,7 @@ private fun SceneScope.SplitShade( lifecycleOwner = lifecycleOwner, modifier = Modifier.align(Alignment.CenterHorizontally) + .sysuiResTag("qs_footer_actions") .then(brightnessMirrorShowingModifier), ) } @@ -475,9 +494,11 @@ private fun SceneScope.SplitShade( NotificationScrollingStack( shadeSession = shadeSession, + stackScrollView = notificationStackScrollView, viewModel = viewModel.notifications, maxScrimTop = { 0f }, shouldPunchHoleBehindScrim = false, + shadeMode = ShadeMode.Split, modifier = Modifier.weight(1f) .fillMaxHeight() 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 5e107c60bee6..931ff56e56cb 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 @@ -3,9 +3,9 @@ package com.android.systemui.shade.ui.composable import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState 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.systemui.shade.ui.viewmodel.ShadeHeaderViewModel @@ -14,8 +14,8 @@ fun VariableDayDate( viewModel: ShadeHeaderViewModel, modifier: Modifier = Modifier, ) { - val longerText = viewModel.longerDateText.collectAsState() - val shorterText = viewModel.shorterDateText.collectAsState() + val longerText = viewModel.longerDateText.collectAsStateWithLifecycle() + val shorterText = viewModel.shorterDateText.collectAsStateWithLifecycle() Layout( contents = diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt index 79d17efcacc1..fe1ebf975303 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncButtonComponent.kt @@ -16,6 +16,7 @@ package com.android.systemui.volume.panel.component.anc.ui.composable +import android.view.Gravity import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -25,11 +26,16 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.clearAndSetSemantics @@ -37,8 +43,10 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.res.R import com.android.systemui.volume.panel.component.anc.ui.viewmodel.AncViewModel +import com.android.systemui.volume.panel.component.popup.ui.composable.VolumePanelPopup import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope import javax.inject.Inject @@ -52,17 +60,24 @@ constructor( @Composable override fun VolumePanelComposeScope.Content(modifier: Modifier) { - val slice by viewModel.buttonSlice.collectAsState() + val slice by viewModel.buttonSlice.collectAsStateWithLifecycle() val label = stringResource(R.string.volume_panel_noise_control_title) + val screenWidth: Float = + with(LocalDensity.current) { LocalConfiguration.current.screenWidthDp.dp.toPx() } + var gravity by remember { mutableIntStateOf(Gravity.CENTER_HORIZONTAL) } val isClickable = viewModel.isClickable(slice) val onClick = if (isClickable) { - { ancPopup.show(null) } + { with(ancPopup) { show(null, gravity) } } } else { null } + Column( - modifier = modifier, + modifier = + modifier.onGloballyPositioned { + gravity = VolumePanelPopup.calculateGravity(it, screenWidth) + }, verticalArrangement = Arrangement.spacedBy(12.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt index e1ee01e78566..15df1be02f56 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/anc/ui/composable/AncPopup.kt @@ -16,17 +16,18 @@ package com.android.systemui.volume.panel.component.anc.ui.composable +import android.view.Gravity import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.slice.Slice import com.android.internal.logging.UiEventLogger import com.android.systemui.animation.Expandable @@ -47,9 +48,10 @@ constructor( ) { /** Shows a popup with the [expandable] animation. */ - fun show(expandable: Expandable?) { + fun show(expandable: Expandable?, horizontalGravity: Int) { uiEventLogger.log(VolumePanelUiEvent.VOLUME_PANEL_ANC_POPUP_SHOWN) - volumePanelPopup.show(expandable, { Title() }, { Content(it) }) + val gravity = horizontalGravity or Gravity.BOTTOM + volumePanelPopup.show(expandable, gravity, { Title() }, { Content(it) }) } @Composable @@ -65,14 +67,14 @@ constructor( @Composable private fun Content(dialog: SystemUIDialog) { - val isAvailable by viewModel.isAvailable.collectAsState(true) + val isAvailable by viewModel.isAvailable.collectAsStateWithLifecycle(true) if (!isAvailable) { SideEffect { dialog.dismiss() } return } - val slice by viewModel.popupSlice.collectAsState() + val slice by viewModel.popupSlice.collectAsStateWithLifecycle() SliceAndroidView( modifier = Modifier.fillMaxWidth(), slice = slice, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt index 0893b9d4c580..e1ae80f13312 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt @@ -16,6 +16,7 @@ package com.android.systemui.volume.panel.component.button.ui.composable +import android.view.Gravity import androidx.compose.foundation.basicMarquee import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -27,20 +28,27 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.Expandable import com.android.systemui.animation.Expandable import com.android.systemui.common.ui.compose.Icon import com.android.systemui.volume.panel.component.button.ui.viewmodel.ButtonViewModel +import com.android.systemui.volume.panel.component.popup.ui.composable.VolumePanelPopup.Companion.calculateGravity import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope import kotlinx.coroutines.flow.StateFlow @@ -48,17 +56,22 @@ import kotlinx.coroutines.flow.StateFlow /** [ComposeVolumePanelUiComponent] implementing a clickable button from a bottom row. */ class ButtonComponent( private val viewModelFlow: StateFlow<ButtonViewModel?>, - private val onClick: (Expandable) -> Unit + private val onClick: (expandable: Expandable, horizontalGravity: Int) -> Unit ) : ComposeVolumePanelUiComponent { @Composable override fun VolumePanelComposeScope.Content(modifier: Modifier) { - val viewModelByState by viewModelFlow.collectAsState() + val viewModelByState by viewModelFlow.collectAsStateWithLifecycle() val viewModel = viewModelByState ?: return val label = viewModel.label.toString() + val screenWidth: Float = + with(LocalDensity.current) { LocalConfiguration.current.screenWidthDp.dp.toPx() } + var gravity by remember { mutableIntStateOf(Gravity.CENTER_HORIZONTAL) } + Column( - modifier = modifier, + modifier = + modifier.onGloballyPositioned { gravity = calculateGravity(it, screenWidth) }, verticalArrangement = Arrangement.spacedBy(12.dp), horizontalAlignment = Alignment.CenterHorizontally, ) { @@ -82,7 +95,7 @@ class ButtonComponent( } else { MaterialTheme.colorScheme.onSurface }, - onClick = onClick, + onClick = { onClick(it, gravity) }, ) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Icon(modifier = Modifier.size(24.dp), icon = viewModel.icon) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt index 12debbc9c011..1b821d36dceb 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt @@ -29,7 +29,6 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -42,6 +41,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.toggleableState import androidx.compose.ui.state.ToggleableState import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.common.ui.compose.Icon import com.android.systemui.volume.panel.component.button.ui.viewmodel.ButtonViewModel import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent @@ -56,7 +56,7 @@ class ToggleButtonComponent( @Composable override fun VolumePanelComposeScope.Content(modifier: Modifier) { - val viewModelByState by viewModelFlow.collectAsState() + val viewModelByState by viewModelFlow.collectAsStateWithLifecycle() val viewModel = viewModelByState ?: return val label = viewModel.label.toString() diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt index ded63a107e70..237bbfd714b9 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/mediaoutput/ui/composable/MediaOutputComponent.kt @@ -45,7 +45,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -55,6 +54,7 @@ import androidx.compose.ui.semantics.liveRegion import androidx.compose.ui.semantics.onClick import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.Expandable import com.android.systemui.common.ui.compose.Icon import com.android.systemui.common.ui.compose.toColor @@ -77,9 +77,9 @@ constructor( @Composable override fun VolumePanelComposeScope.Content(modifier: Modifier) { val connectedDeviceViewModel: ConnectedDeviceViewModel? by - viewModel.connectedDeviceViewModel.collectAsState() + viewModel.connectedDeviceViewModel.collectAsStateWithLifecycle() val deviceIconViewModel: DeviceIconViewModel? by - viewModel.deviceIconViewModel.collectAsState() + viewModel.deviceIconViewModel.collectAsStateWithLifecycle() val clickLabel = stringResource(R.string.volume_panel_enter_media_output_settings) Expandable( diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt index bb4e9574c602..3b1bf2ab9dcd 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/popup/ui/composable/VolumePanelPopup.kt @@ -17,6 +17,7 @@ package com.android.systemui.volume.panel.component.popup.ui.composable import android.view.Gravity +import androidx.annotation.GravityInt import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -31,6 +32,8 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.LayoutCoordinates +import androidx.compose.ui.layout.boundsInRoot import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.paneTitle @@ -60,13 +63,14 @@ constructor( */ fun show( expandable: Expandable?, + @GravityInt gravity: Int, title: @Composable (SystemUIDialog) -> Unit, content: @Composable (SystemUIDialog) -> Unit, ) { val dialog = dialogFactory.create( theme = R.style.Theme_VolumePanel_Popup, - dialogGravity = Gravity.BOTTOM, + dialogGravity = gravity, ) { PopupComposable(it, title, content) } @@ -122,4 +126,23 @@ constructor( } } } + + companion object { + + /** + * Returns absolute ([Gravity.LEFT], [Gravity.RIGHT] or [Gravity.CENTER_HORIZONTAL]) + * [GravityInt] for the popup based on the [coordinates] global position relative to the + * [screenWidthPx]. + */ + @GravityInt + fun calculateGravity(coordinates: LayoutCoordinates, screenWidthPx: Float): Int { + val bottomCenter: Float = coordinates.boundsInRoot().bottomCenter.x + val rootBottomCenter: Float = screenWidthPx / 2 + return when { + bottomCenter < rootBottomCenter -> Gravity.LEFT + bottomCenter > rootBottomCenter -> Gravity.RIGHT + else -> Gravity.CENTER_HORIZONTAL + } + } + } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt index 12d2bc2e274b..9891b5b5eba2 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/spatialaudio/ui/composable/SpatialAudioPopup.kt @@ -16,17 +16,18 @@ package com.android.systemui.volume.panel.component.spatialaudio.ui.composable +import android.view.Gravity import androidx.compose.foundation.basicMarquee import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.internal.logging.UiEventLogger import com.android.systemui.animation.Expandable import com.android.systemui.common.ui.compose.Icon @@ -47,14 +48,15 @@ constructor( ) { /** Shows a popup with the [expandable] animation. */ - fun show(expandable: Expandable) { + fun show(expandable: Expandable, horizontalGravity: Int) { uiEventLogger.logWithPosition( VolumePanelUiEvent.VOLUME_PANEL_SPATIAL_AUDIO_POP_UP_SHOWN, 0, null, viewModel.spatialAudioButtons.value.indexOfFirst { it.button.isActive } ) - volumePanelPopup.show(expandable, { Title() }, { Content(it) }) + val gravity = horizontalGravity or Gravity.BOTTOM + volumePanelPopup.show(expandable, gravity, { Title() }, { Content(it) }) } @Composable @@ -70,14 +72,14 @@ constructor( @Composable private fun Content(dialog: SystemUIDialog) { - val isAvailable by viewModel.isAvailable.collectAsState() + val isAvailable by viewModel.isAvailable.collectAsStateWithLifecycle() if (!isAvailable) { SideEffect { dialog.dismiss() } return } - val enabledModelStates by viewModel.spatialAudioButtons.collectAsState() + val enabledModelStates by viewModel.spatialAudioButtons.collectAsStateWithLifecycle() if (enabledModelStates.isEmpty()) { return } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt index a3467f2ab78e..072e91a25444 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/ColumnVolumeSliders.kt @@ -20,6 +20,8 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.EnterTransition import androidx.compose.animation.ExitTransition import androidx.compose.animation.ExperimentalAnimationApi +import androidx.compose.animation.core.AnimationSpec +import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.tween import androidx.compose.animation.core.updateTransition import androidx.compose.animation.expandVertically @@ -28,10 +30,8 @@ import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut import androidx.compose.animation.shrinkVertically -import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -39,7 +39,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.IconButtonDefaults import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.State import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -49,15 +49,22 @@ import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.stateDescription +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.PlatformSliderColors +import com.android.compose.modifiers.padding import com.android.systemui.res.R import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel private const val EXPAND_DURATION_MILLIS = 500 +private const val COLLAPSE_EXPAND_BUTTON_DELAY_MILLIS = 350 private const val COLLAPSE_DURATION_MILLIS = 300 +private const val EXPAND_BUTTON_ANIMATION_DURATION_MILLIS = 350 +private const val TOP_SLIDER_ANIMATION_DURATION_MILLIS = 400 private const val SHRINK_FRACTION = 0.55f private const val SCALE_FRACTION = 0.9f +private const val EXPAND_BUTTON_SCALE = 0.8f /** Volume sliders laid out in a collapsable column */ @OptIn(ExperimentalAnimationApi::class) @@ -73,14 +80,15 @@ fun ColumnVolumeSliders( require(viewModels.isNotEmpty()) val transition = updateTransition(isExpanded, label = "CollapsableSliders") Column(modifier = modifier) { - Row( + Box( modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp), ) { val sliderViewModel: SliderViewModel = viewModels.first() - val sliderState by viewModels.first().slider.collectAsState() + val sliderState by viewModels.first().slider.collectAsStateWithLifecycle() + val sliderPadding by topSliderPadding(isExpandable) + VolumeSlider( - modifier = Modifier.weight(1f), + modifier = Modifier.padding(end = { sliderPadding.roundToPx() }).fillMaxWidth(), state = sliderState, onValueChange = { newValue: Float -> sliderViewModel.onValueChanged(sliderState, newValue) @@ -90,21 +98,13 @@ fun ColumnVolumeSliders( sliderColors = sliderColors, ) - val expandButtonStateDescription = - if (isExpanded) stringResource(R.string.volume_panel_expanded_sliders) - else stringResource(R.string.volume_panel_collapsed_sliders) - if (isExpandable) { - ExpandButton( - modifier = - Modifier.semantics { - role = Role.Switch - stateDescription = expandButtonStateDescription - }, - isExpanded = isExpanded, - onExpandedChanged = onExpandedChanged, - sliderColors = sliderColors, - ) - } + ExpandButton( + modifier = Modifier.align(Alignment.CenterEnd), + isExpanded = isExpanded, + isExpandable = isExpandable, + onExpandedChanged = onExpandedChanged, + sliderColors = sliderColors, + ) } transition.AnimatedVisibility( visible = { it || !isExpandable }, @@ -119,7 +119,7 @@ fun ColumnVolumeSliders( Column { for (index in 1..viewModels.lastIndex) { val sliderViewModel: SliderViewModel = viewModels[index] - val sliderState by sliderViewModel.slider.collectAsState() + val sliderState by sliderViewModel.slider.collectAsStateWithLifecycle() transition.AnimatedVisibility( modifier = Modifier.padding(top = 16.dp), visible = { it || !isExpandable }, @@ -147,30 +147,48 @@ fun ColumnVolumeSliders( @Composable private fun ExpandButton( isExpanded: Boolean, + isExpandable: Boolean, onExpandedChanged: (Boolean) -> Unit, sliderColors: PlatformSliderColors, modifier: Modifier = Modifier, ) { - IconButton( - modifier = modifier.size(64.dp), - onClick = { onExpandedChanged(!isExpanded) }, - colors = - IconButtonDefaults.filledIconButtonColors( - containerColor = sliderColors.indicatorColor, - contentColor = sliderColors.iconColor - ), + val expandButtonStateDescription = + if (isExpanded) { + stringResource(R.string.volume_panel_expanded_sliders) + } else { + stringResource(R.string.volume_panel_collapsed_sliders) + } + AnimatedVisibility( + modifier = modifier, + visible = isExpandable, + enter = expandButtonEnterTransition(), + exit = expandButtonExitTransition(), ) { - Icon( - painter = - painterResource( - if (isExpanded) { - R.drawable.ic_filled_arrow_down - } else { - R.drawable.ic_filled_arrow_up - } + IconButton( + modifier = + Modifier.size(64.dp).semantics { + role = Role.Switch + stateDescription = expandButtonStateDescription + }, + onClick = { onExpandedChanged(!isExpanded) }, + colors = + IconButtonDefaults.filledIconButtonColors( + containerColor = sliderColors.indicatorColor, + contentColor = sliderColors.iconColor ), - contentDescription = null, - ) + ) { + Icon( + painter = + painterResource( + if (isExpanded) { + R.drawable.ic_filled_arrow_down + } else { + R.drawable.ic_filled_arrow_up + } + ), + contentDescription = null, + ) + } } } @@ -204,3 +222,63 @@ private fun exitTransition(index: Int, totalCount: Int): ExitTransition { ) + fadeOut(animationSpec = tween(durationMillis = exitDuration)) } + +private fun expandButtonEnterTransition(): EnterTransition { + return fadeIn( + tween( + delayMillis = COLLAPSE_EXPAND_BUTTON_DELAY_MILLIS, + durationMillis = EXPAND_BUTTON_ANIMATION_DURATION_MILLIS, + ) + ) + + scaleIn( + animationSpec = + tween( + delayMillis = COLLAPSE_EXPAND_BUTTON_DELAY_MILLIS, + durationMillis = EXPAND_BUTTON_ANIMATION_DURATION_MILLIS, + ), + initialScale = EXPAND_BUTTON_SCALE, + ) +} + +private fun expandButtonExitTransition(): ExitTransition { + return fadeOut( + tween( + delayMillis = EXPAND_DURATION_MILLIS, + durationMillis = EXPAND_BUTTON_ANIMATION_DURATION_MILLIS, + ) + ) + + scaleOut( + animationSpec = + tween( + delayMillis = EXPAND_DURATION_MILLIS, + durationMillis = EXPAND_BUTTON_ANIMATION_DURATION_MILLIS, + ), + targetScale = EXPAND_BUTTON_SCALE, + ) +} + +@Composable +private fun topSliderPadding(isExpandable: Boolean): State<Dp> { + val animationSpec: AnimationSpec<Dp> = + if (isExpandable) { + tween( + delayMillis = COLLAPSE_DURATION_MILLIS, + durationMillis = TOP_SLIDER_ANIMATION_DURATION_MILLIS, + ) + } else { + tween( + delayMillis = EXPAND_DURATION_MILLIS, + durationMillis = TOP_SLIDER_ANIMATION_DURATION_MILLIS, + ) + } + return animateDpAsState( + targetValue = + if (isExpandable) { + 72.dp + } else { + 0.dp + }, + animationSpec = animationSpec, + label = "TopVolumeSliderPadding" + ) +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt index bb17499f021f..d15430faa0a0 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/GridVolumeSliders.kt @@ -18,9 +18,9 @@ package com.android.systemui.volume.panel.component.volume.ui.composable import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.PlatformSliderColors import com.android.compose.grid.VerticalGrid import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel @@ -39,7 +39,7 @@ fun GridVolumeSliders( horizontalSpacing = 24.dp, ) { for (sliderViewModel in viewModels) { - val sliderState = sliderViewModel.slider.collectAsState().value + val sliderState = sliderViewModel.slider.collectAsStateWithLifecycle().value VolumeSlider( modifier = Modifier.fillMaxWidth(), state = sliderState, diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt index fdf8ee872019..770c5d5c247c 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/volume/ui/composable/VolumeSlidersComponent.kt @@ -18,12 +18,13 @@ package com.android.systemui.volume.panel.component.volume.ui.composable import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.PlatformSliderDefaults import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.SliderViewModel import com.android.systemui.volume.panel.component.volume.ui.viewmodel.AudioVolumeComponentViewModel +import com.android.systemui.volume.panel.component.volume.ui.viewmodel.SlidersExpandableViewModel import com.android.systemui.volume.panel.ui.composable.ComposeVolumePanelUiComponent import com.android.systemui.volume.panel.ui.composable.VolumePanelComposeScope import com.android.systemui.volume.panel.ui.composable.isPortrait @@ -37,7 +38,8 @@ constructor( @Composable override fun VolumePanelComposeScope.Content(modifier: Modifier) { - val sliderViewModels: List<SliderViewModel> by viewModel.sliderViewModels.collectAsState() + val sliderViewModels: List<SliderViewModel> by + viewModel.sliderViewModels.collectAsStateWithLifecycle() if (sliderViewModels.isEmpty()) { return } @@ -48,13 +50,21 @@ constructor( modifier = modifier.fillMaxWidth(), ) } else { - val isExpanded by viewModel.isExpanded.collectAsState() + val expandableViewModel: SlidersExpandableViewModel by + viewModel + .isExpandable(isPortrait) + .collectAsStateWithLifecycle(SlidersExpandableViewModel.Unavailable) + if (expandableViewModel is SlidersExpandableViewModel.Unavailable) { + return + } + val isExpanded = + (expandableViewModel as? SlidersExpandableViewModel.Expandable)?.isExpanded ?: true ColumnVolumeSliders( viewModels = sliderViewModels, isExpanded = isExpanded, onExpandedChanged = viewModel::onExpandedChanged, sliderColors = PlatformSliderDefaults.defaultPlatformSliderColors(), - isExpandable = isPortrait, + isExpandable = expandableViewModel is SlidersExpandableViewModel.Expandable, modifier = modifier.fillMaxWidth(), ) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt index a602e25e05c1..83b8158a9bcf 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/ui/composable/VolumePanelRoot.kt @@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -32,6 +31,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.paneTitle import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.res.R import com.android.systemui.volume.panel.ui.layout.ComponentsLayout import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelState @@ -54,8 +54,8 @@ fun VolumePanelRoot( } val accessibilityTitle = stringResource(R.string.accessibility_volume_settings) - val state: VolumePanelState by viewModel.volumePanelState.collectAsState() - val components by viewModel.componentsLayout.collectAsState(null) + val state: VolumePanelState by viewModel.volumePanelState.collectAsStateWithLifecycle() + val components by viewModel.componentsLayout.collectAsStateWithLifecycle(null) with(VolumePanelComposeScope(state)) { components?.let { componentsState -> diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt index d924d88d1e59..92d5c26148e4 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/ObservableTransitionState.kt @@ -74,6 +74,16 @@ sealed interface ObservableTransitionState { */ val isUserInputOngoing: Flow<Boolean>, ) : ObservableTransitionState + + fun isIdle(scene: SceneKey?): Boolean { + return this is Idle && (scene == null || this.currentScene == scene) + } + + fun isTransitioning(from: SceneKey? = null, to: SceneKey? = null): Boolean { + return this is Transition && + (from == null || this.fromScene == from) && + (to == null || this.toScene == to) + } } /** diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt index 47a00f408460..624f18d53a70 100644 --- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt +++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt @@ -133,7 +133,7 @@ class ColorScheme( @ColorInt seed: Int, darkTheme: Boolean, style: Style - ) : this(seed, darkTheme, style, 0.5) + ) : this(seed, darkTheme, style, 0.0) @JvmOverloads constructor( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java index f4ad7649a18f..9b1d4eca8b2b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java @@ -84,7 +84,6 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.domain.interactor.LogContextInteractor; -import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor; import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor; import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel; import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel; @@ -161,8 +160,6 @@ public class AuthControllerTest extends SysuiTestCase { @Mock private InteractionJankMonitor mInteractionJankMonitor; @Mock - private PromptCredentialInteractor mBiometricPromptCredentialInteractor; - @Mock private PromptSelectorInteractor mPromptSelectionInteractor; @Mock private CredentialViewModel mCredentialViewModel; @@ -1057,7 +1054,6 @@ public class AuthControllerTest extends SysuiTestCase { private final class TestableAuthController extends AuthController { private int mBuildCount = 0; - private PromptInfo mLastBiometricPromptInfo; TestableAuthController(Context context) { super(context, null /* applicationCoroutineScope */, @@ -1065,8 +1061,8 @@ public class AuthControllerTest extends SysuiTestCase { mFingerprintManager, mFaceManager, () -> mUdfpsController, mDisplayManager, mWakefulnessLifecycle, mPanelInteractionDetector, mUserManager, mLockPatternUtils, () -> mUdfpsLogger, () -> mLogContextInteractor, - () -> mBiometricPromptCredentialInteractor, () -> mPromptSelectionInteractor, - () -> mCredentialViewModel, () -> mPromptViewModel, mInteractionJankMonitor, + () -> mPromptSelectionInteractor, () -> mCredentialViewModel, + () -> mPromptViewModel, mInteractionJankMonitor, mHandler, mBackgroundExecutor, mUdfpsUtils, mVibratorHelper); } @@ -1079,8 +1075,6 @@ public class AuthControllerTest extends SysuiTestCase { UserManager userManager, LockPatternUtils lockPatternUtils, PromptViewModel viewModel) { - mLastBiometricPromptInfo = promptInfo; - AuthDialog dialog; if (mBuildCount == 0) { dialog = mDialog1; diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt index 1cdc2b69034b..407bf4cac633 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalMediaRepositoryImplTest.kt @@ -114,7 +114,7 @@ class CommunalMediaRepositoryImplTest : SysuiTestCase() { // Change to media unavailable and notify the listener. whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(false) - mediaDataListenerCaptor.value.onMediaDataRemoved("key") + mediaDataListenerCaptor.value.onMediaDataRemoved("key", false) runCurrent() // Media active now returns false. diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt index ce7b60e86f8f..325a324da8ad 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSettingsRepositoryImplTest.kt @@ -29,6 +29,7 @@ import android.platform.test.annotations.EnableFlags import android.provider.Settings import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.settingslib.flags.Flags.FLAG_ALLOW_ALL_WIDGETS_ON_LOCKSCREEN_BY_DEFAULT import com.android.systemui.Flags.FLAG_COMMUNAL_HUB import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.broadcastDispatcher @@ -202,6 +203,18 @@ class CommunalSettingsRepositoryImplTest : SysuiTestCase() { .isEqualTo(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD) } + @EnableFlags(FLAG_COMMUNAL_HUB, FLAG_ALLOW_ALL_WIDGETS_ON_LOCKSCREEN_BY_DEFAULT) + @Test + fun hubShowsAllWidgetsByDefaultWhenFlagEnabled() = + testScope.runTest { + val setting by collectLastValue(underTest.getWidgetCategories(PRIMARY_USER)) + assertThat(setting?.categories) + .isEqualTo( + AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD + + AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN + ) + } + private fun setKeyguardFeaturesDisabled(user: UserInfo, disabledFlags: Int) { whenever(kosmos.devicePolicyManager.getKeyguardDisabledFeatures(nullable(), eq(user.id))) .thenReturn(disabledFlags) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt index 1f8cb8a2fc9b..2d079d7488d0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt @@ -44,7 +44,6 @@ import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.communal.ui.viewmodel.CommunalViewModel.Companion.POPUP_AUTO_HIDE_TIMEOUT_MS import com.android.systemui.communal.ui.viewmodel.PopupType import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED import com.android.systemui.flags.andSceneContainer import com.android.systemui.flags.fakeFeatureFlagsClassic @@ -145,7 +144,6 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { kosmos.communalInteractor, kosmos.communalTutorialInteractor, kosmos.shadeInteractor, - kosmos.deviceEntryInteractor, mediaHost, logcatLogBuffer("CommunalViewModelTest"), ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java index e3dd9aefa6d0..8bfa5cff8b97 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.DreamManager; import android.content.res.Resources; import android.graphics.Region; import android.os.Handler; @@ -45,8 +46,10 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController; import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor; import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback; +import com.android.systemui.communal.domain.interactor.CommunalInteractor; import com.android.systemui.complication.ComplicationHostViewController; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; +import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.BlurUtils; import kotlinx.coroutines.CoroutineDispatcher; @@ -115,6 +118,12 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { DreamOverlayStateController mStateController; @Mock KeyguardTransitionInteractor mKeyguardTransitionInteractor; + @Mock + ShadeInteractor mShadeInteractor; + @Mock + CommunalInteractor mCommunalInteractor; + @Mock + private DreamManager mDreamManager; DreamOverlayContainerViewController mController; @@ -146,7 +155,10 @@ public class DreamOverlayContainerViewControllerTest extends SysuiTestCase { mAnimationsController, mStateController, mBouncerlessScrimController, - mKeyguardTransitionInteractor); + mKeyguardTransitionInteractor, + mShadeInteractor, + mCommunalInteractor, + mDreamManager); } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorTest.kt index feb72989980c..7292985b2dba 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/homecontrols/HomeControlsComponentInteractorTest.kt @@ -33,7 +33,6 @@ import com.android.systemui.controls.panels.SelectedComponentRepository import com.android.systemui.controls.panels.authorizedPanelsRepository import com.android.systemui.controls.panels.selectedComponentRepository import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.dreams.homecontrols.domain.interactor.HomeControlsComponentInteractor import com.android.systemui.dreams.homecontrols.domain.interactor.HomeControlsComponentInteractor.Companion.MAX_UPDATE_CORRELATION_DELAY import com.android.systemui.kosmos.testScope import com.android.systemui.settings.fakeUserTracker @@ -64,7 +63,7 @@ class HomeControlsComponentInteractorTest : SysuiTestCase() { private val kosmos = testKosmos() - private lateinit var underTest: HomeControlsComponentInteractor + private val underTest by lazy { kosmos.homeControlsComponentInteractor } @Before fun setUp() = @@ -73,8 +72,7 @@ class HomeControlsComponentInteractorTest : SysuiTestCase() { fakeUserRepository.setUserInfos(listOf(PRIMARY_USER, ANOTHER_USER)) whenever(controlsComponent.getControlsListingController()) .thenReturn(Optional.of(controlsListingController)) - - underTest = homeControlsComponentInteractor + Unit } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt index e270d9efec97..519bb6eb7834 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModelTest.kt @@ -62,8 +62,8 @@ class AodBurnInViewModelTest : SysuiTestCase() { private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository private val keyguardClockRepository = kosmos.fakeKeyguardClockRepository private lateinit var underTest: AodBurnInViewModel - - private var burnInParameters = BurnInParameters() + // assign a smaller value to minViewY to avoid overflow + private var burnInParameters = BurnInParameters(minViewY = Int.MAX_VALUE / 2) private val burnInFlow = MutableStateFlow(BurnInModel()) @Before @@ -296,52 +296,111 @@ class AodBurnInViewModelTest : SysuiTestCase() { scale = 0.5f, ) - assertThat(movement?.translationX).isEqualTo(0) - assertThat(movement?.translationY).isEqualTo(0) + assertThat(movement?.translationX).isEqualTo(20) + assertThat(movement?.translationY).isEqualTo(30) assertThat(movement?.scale).isEqualTo(0.5f) assertThat(movement?.scaleClockOnly).isEqualTo(false) } @Test + fun translationAndScale_composeFlagOff_weatherLargeClock() = + testBurnInViewModelForClocks( + isSmallClock = false, + isWeatherClock = true, + expectedScaleOnly = false, + enableMigrateClocksToBlueprintFlag = true, + enableComposeLockscreenFlag = false + ) + + @Test + fun translationAndScale_composeFlagOff_weatherSmallClock() = + testBurnInViewModelForClocks( + isSmallClock = true, + isWeatherClock = true, + expectedScaleOnly = false, + enableMigrateClocksToBlueprintFlag = true, + enableComposeLockscreenFlag = false + ) + + @Test + fun translationAndScale_composeFlagOff_nonWeatherLargeClock() = + testBurnInViewModelForClocks( + isSmallClock = false, + isWeatherClock = false, + expectedScaleOnly = true, + enableMigrateClocksToBlueprintFlag = true, + enableComposeLockscreenFlag = false + ) + + @Test + fun translationAndScale_composeFlagOff_nonWeatherSmallClock() = + testBurnInViewModelForClocks( + isSmallClock = true, + isWeatherClock = false, + expectedScaleOnly = false, + enableMigrateClocksToBlueprintFlag = true, + enableComposeLockscreenFlag = false + ) + + @Test fun translationAndScale_composeFlagOn_weatherLargeClock() = - testBurnInViewModelWhenComposeFlagOn( + testBurnInViewModelForClocks( isSmallClock = false, isWeatherClock = true, - expectedScaleOnly = false + expectedScaleOnly = false, + enableMigrateClocksToBlueprintFlag = true, + enableComposeLockscreenFlag = true ) @Test fun translationAndScale_composeFlagOn_weatherSmallClock() = - testBurnInViewModelWhenComposeFlagOn( + testBurnInViewModelForClocks( isSmallClock = true, isWeatherClock = true, - expectedScaleOnly = true + expectedScaleOnly = false, + enableMigrateClocksToBlueprintFlag = true, + enableComposeLockscreenFlag = true ) @Test fun translationAndScale_composeFlagOn_nonWeatherLargeClock() = - testBurnInViewModelWhenComposeFlagOn( + testBurnInViewModelForClocks( isSmallClock = false, isWeatherClock = false, - expectedScaleOnly = true + expectedScaleOnly = true, + enableMigrateClocksToBlueprintFlag = true, + enableComposeLockscreenFlag = true ) @Test fun translationAndScale_composeFlagOn_nonWeatherSmallClock() = - testBurnInViewModelWhenComposeFlagOn( + testBurnInViewModelForClocks( isSmallClock = true, isWeatherClock = false, - expectedScaleOnly = true + expectedScaleOnly = false, + enableMigrateClocksToBlueprintFlag = true, + enableComposeLockscreenFlag = true ) - private fun testBurnInViewModelWhenComposeFlagOn( + private fun testBurnInViewModelForClocks( isSmallClock: Boolean, isWeatherClock: Boolean, - expectedScaleOnly: Boolean + expectedScaleOnly: Boolean, + enableMigrateClocksToBlueprintFlag: Boolean, + enableComposeLockscreenFlag: Boolean ) = testScope.runTest { - mSetFlagsRule.enableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) - mSetFlagsRule.enableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN) + if (enableMigrateClocksToBlueprintFlag) { + mSetFlagsRule.enableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) + } else { + mSetFlagsRule.disableFlags(AConfigFlags.FLAG_MIGRATE_CLOCKS_TO_BLUEPRINT) + } + + if (enableComposeLockscreenFlag) { + mSetFlagsRule.enableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN) + } else { + mSetFlagsRule.disableFlags(AConfigFlags.FLAG_COMPOSE_LOCKSCREEN) + } if (isSmallClock) { keyguardClockRepository.setClockSize(ClockSize.SMALL) // we need the following step to update stateFlow value diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt index bc9d257b3836..f46ca002a103 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt @@ -24,6 +24,7 @@ import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.SwipeDirection +import com.android.compose.animation.scene.TransitionKey import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.authentication.data.repository.fakeAuthenticationRepository @@ -39,6 +40,7 @@ import com.android.systemui.power.data.repository.fakePowerRepository import com.android.systemui.power.shared.model.WakefulnessState import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.scene.shared.model.TransitionKeys import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.shared.model.ShadeMode @@ -117,6 +119,17 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { } } + private fun expectedDownTransitionKey( + isSingleShade: Boolean, + isShadeTouchable: Boolean, + ): TransitionKey? { + return when { + !isShadeTouchable -> null + !isSingleShade -> TransitionKeys.ToSplitShade + else -> null + } + } + private fun expectedUpDestination( canSwipeToEnter: Boolean, isShadeTouchable: Boolean, @@ -184,18 +197,16 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { ) val destinationScenes by collectLastValue(underTest.destinationScenes) - - assertThat( - destinationScenes - ?.get( - Swipe( - SwipeDirection.Down, - fromSource = Edge.Top.takeIf { downFromEdge }, - pointerCount = if (downWithTwoPointers) 2 else 1, - ) - ) - ?.toScene + val downDestination = + destinationScenes?.get( + Swipe( + SwipeDirection.Down, + fromSource = Edge.Top.takeIf { downFromEdge }, + pointerCount = if (downWithTwoPointers) 2 else 1, + ) ) + + assertThat(downDestination?.toScene) .isEqualTo( expectedDownDestination( downFromEdge = downFromEdge, @@ -204,6 +215,14 @@ class LockscreenSceneViewModelTest : SysuiTestCase() { ) ) + assertThat(downDestination?.transitionKey) + .isEqualTo( + expectedDownTransitionKey( + isSingleShade = isSingleShade, + isShadeTouchable = isShadeTouchable, + ) + ) + assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.toScene) .isEqualTo( expectedUpDestination( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt index 1e5f31401e20..7a37a9e03b16 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/data/repository/MediaFilterRepositoryTest.kt @@ -150,7 +150,7 @@ class MediaFilterRepositoryTest : SysuiTestCase() { @Test fun addMediaControlPlayingThenRemote() = testScope.runTest { - val sortedMedia by collectLastValue(underTest.sortedMedia) + val currentMedia by collectLastValue(underTest.currentMedia) val playingInstanceId = InstanceId.fakeInstanceId(123) val remoteInstanceId = InstanceId.fakeInstanceId(321) val playingData = createMediaData("app1", true, LOCAL, false, playingInstanceId) @@ -161,8 +161,8 @@ class MediaFilterRepositoryTest : SysuiTestCase() { underTest.addSelectedUserMediaEntry(remoteData) underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(remoteInstanceId)) - assertThat(sortedMedia?.size).isEqualTo(2) - assertThat(sortedMedia?.values) + assertThat(currentMedia?.size).isEqualTo(2) + assertThat(currentMedia) .containsExactly( MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId)), MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(remoteInstanceId)) @@ -173,7 +173,7 @@ class MediaFilterRepositoryTest : SysuiTestCase() { @Test fun switchMediaControlsPlaying() = testScope.runTest { - val sortedMedia by collectLastValue(underTest.sortedMedia) + val currentMedia by collectLastValue(underTest.currentMedia) val playingInstanceId1 = InstanceId.fakeInstanceId(123) val playingInstanceId2 = InstanceId.fakeInstanceId(321) var playingData1 = createMediaData("app1", true, LOCAL, false, playingInstanceId1) @@ -184,8 +184,8 @@ class MediaFilterRepositoryTest : SysuiTestCase() { underTest.addSelectedUserMediaEntry(playingData2) underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(playingInstanceId2)) - assertThat(sortedMedia?.size).isEqualTo(2) - assertThat(sortedMedia?.values) + assertThat(currentMedia?.size).isEqualTo(2) + assertThat(currentMedia) .containsExactly( MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId1)), MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId2)) @@ -198,12 +198,28 @@ class MediaFilterRepositoryTest : SysuiTestCase() { underTest.addSelectedUserMediaEntry(playingData1) underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(playingInstanceId1)) underTest.addSelectedUserMediaEntry(playingData2) - underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(playingInstanceId2)) + underTest.addMediaDataLoadingState( + MediaDataLoadingModel.Loaded(playingInstanceId2, false) + ) - assertThat(sortedMedia?.size).isEqualTo(2) - assertThat(sortedMedia?.values) + assertThat(currentMedia?.size).isEqualTo(2) + assertThat(currentMedia) .containsExactly( - MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId2)), + MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId1)), + MediaCommonModel.MediaControl( + MediaDataLoadingModel.Loaded(playingInstanceId2, false) + ) + ) + .inOrder() + + underTest.setOrderedMedia() + + assertThat(currentMedia?.size).isEqualTo(2) + assertThat(currentMedia) + .containsExactly( + MediaCommonModel.MediaControl( + MediaDataLoadingModel.Loaded(playingInstanceId2, false) + ), MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(playingInstanceId1)) ) .inOrder() @@ -212,7 +228,7 @@ class MediaFilterRepositoryTest : SysuiTestCase() { @Test fun fullOrderTest() = testScope.runTest { - val sortedMedia by collectLastValue(underTest.sortedMedia) + val currentMedia by collectLastValue(underTest.currentMedia) val instanceId1 = InstanceId.fakeInstanceId(123) val instanceId2 = InstanceId.fakeInstanceId(456) val instanceId3 = InstanceId.fakeInstanceId(321) @@ -252,8 +268,8 @@ class MediaFilterRepositoryTest : SysuiTestCase() { SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE, true) ) - assertThat(sortedMedia?.size).isEqualTo(6) - assertThat(sortedMedia?.values) + assertThat(currentMedia?.size).isEqualTo(6) + assertThat(currentMedia) .containsExactly( MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(instanceId1)), MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(instanceId2)), @@ -270,7 +286,7 @@ class MediaFilterRepositoryTest : SysuiTestCase() { @Test fun loadMediaFromRec() = testScope.runTest { - val isMediaFromRec by collectLastValue(underTest.isMediaFromRec) + val currentMedia by collectLastValue(underTest.currentMedia) val instanceId1 = InstanceId.fakeInstanceId(123) val instanceId2 = InstanceId.fakeInstanceId(456) val data = @@ -278,22 +294,59 @@ class MediaFilterRepositoryTest : SysuiTestCase() { active = true, instanceId = instanceId1, packageName = PACKAGE_NAME, - isPlaying = true + isPlaying = true, + notificationKey = KEY, + ) + val newData = + MediaData( + active = true, + instanceId = instanceId2, + isPlaying = true, + notificationKey = KEY_2 + ) + val icon = Icon.createWithResource(context, R.drawable.ic_media_play) + val mediaRecommendations = + SmartspaceMediaData( + targetId = KEY_MEDIA_SMARTSPACE, + isActive = true, + packageName = PACKAGE_NAME, + recommendations = MediaTestHelper.getValidRecommendationList(icon), ) - val newData = MediaData(active = true, instanceId = instanceId2) - - assertThat(isMediaFromRec).isFalse() underTest.setMediaFromRecPackageName(PACKAGE_NAME) underTest.addSelectedUserMediaEntry(data) + underTest.setRecommendation(mediaRecommendations) + underTest.setRecommendationsLoadingState( + SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE) + ) underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId1)) - assertThat(isMediaFromRec).isTrue() + assertThat(currentMedia) + .containsExactly( + MediaCommonModel.MediaControl( + MediaDataLoadingModel.Loaded(instanceId1), + isMediaFromRec = true + ), + MediaCommonModel.MediaRecommendations( + SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE) + ) + ) + .inOrder() underTest.addSelectedUserMediaEntry(newData) + underTest.addSelectedUserMediaEntry(data.copy(isPlaying = false)) underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId2)) + underTest.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId1)) - assertThat(isMediaFromRec).isFalse() + assertThat(currentMedia) + .containsExactly( + MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(instanceId2)), + MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(instanceId1)), + MediaCommonModel.MediaRecommendations( + SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE) + ) + ) + .inOrder() } private fun createMediaData( @@ -316,6 +369,7 @@ class MediaFilterRepositoryTest : SysuiTestCase() { private const val LOCAL = MediaData.PLAYBACK_LOCAL private const val REMOTE = MediaData.PLAYBACK_CAST_LOCAL private const val KEY = "KEY" + private const val KEY_2 = "KEY_2" private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID" private const val PACKAGE_NAME = "com.android.example" } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt index e44affc7262b..39dbc7e8cb5b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt @@ -55,6 +55,14 @@ class MediaCarouselInteractorTest : SysuiTestCase() { private val mediaFilterRepository: MediaFilterRepository = kosmos.mediaFilterRepository private val mediaRecommendationsInteractor: MediaRecommendationsInteractor = kosmos.mediaRecommendationsInteractor + val icon = Icon.createWithResource(context, R.drawable.ic_media_play) + private val mediaRecommendation = + SmartspaceMediaData( + targetId = KEY_MEDIA_SMARTSPACE, + isActive = true, + packageName = PACKAGE_NAME, + recommendations = MediaTestHelper.getValidRecommendationList(icon), + ) private val underTest: MediaCarouselInteractor = kosmos.mediaCarouselInteractor @@ -122,26 +130,19 @@ class MediaCarouselInteractorTest : SysuiTestCase() { collectLastValue(underTest.hasActiveMediaOrRecommendation) val hasAnyMediaOrRecommendation by collectLastValue(underTest.hasAnyMediaOrRecommendation) - val sortedMedia by collectLastValue(underTest.sortedMedia) + val currentMedia by collectLastValue(underTest.currentMedia) kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false) - val icon = Icon.createWithResource(context, R.drawable.ic_media_play) - val userMediaRecommendation = - SmartspaceMediaData( - targetId = KEY_MEDIA_SMARTSPACE, - isActive = true, - recommendations = MediaTestHelper.getValidRecommendationList(icon), - ) val userMedia = MediaData(active = false) val recsLoadingModel = SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE, true) val mediaLoadingModel = MediaDataLoadingModel.Loaded(userMedia.instanceId) - mediaFilterRepository.setRecommendation(userMediaRecommendation) + mediaFilterRepository.setRecommendation(mediaRecommendation) mediaFilterRepository.setRecommendationsLoadingState(recsLoadingModel) assertThat(hasActiveMediaOrRecommendation).isTrue() assertThat(hasAnyMediaOrRecommendation).isTrue() - assertThat(sortedMedia) + assertThat(currentMedia) .containsExactly(MediaCommonModel.MediaRecommendations(recsLoadingModel)) mediaFilterRepository.addSelectedUserMediaEntry(userMedia) @@ -149,7 +150,7 @@ class MediaCarouselInteractorTest : SysuiTestCase() { assertThat(hasActiveMediaOrRecommendation).isTrue() assertThat(hasAnyMediaOrRecommendation).isTrue() - assertThat(sortedMedia) + assertThat(currentMedia) .containsExactly( MediaCommonModel.MediaRecommendations(recsLoadingModel), MediaCommonModel.MediaControl(mediaLoadingModel, true) @@ -166,14 +167,6 @@ class MediaCarouselInteractorTest : SysuiTestCase() { collectLastValue(underTest.hasAnyMediaOrRecommendation) kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false) - val icon = Icon.createWithResource(context, R.drawable.ic_media_play) - val mediaRecommendation = - SmartspaceMediaData( - targetId = KEY_MEDIA_SMARTSPACE, - isActive = true, - recommendations = MediaTestHelper.getValidRecommendationList(icon), - ) - mediaFilterRepository.setRecommendation(mediaRecommendation) assertThat(hasActiveMediaOrRecommendation).isTrue() @@ -194,14 +187,6 @@ class MediaCarouselInteractorTest : SysuiTestCase() { collectLastValue(underTest.hasAnyMediaOrRecommendation) kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false) - val icon = Icon.createWithResource(context, R.drawable.ic_media_play) - val mediaRecommendation = - SmartspaceMediaData( - targetId = KEY_MEDIA_SMARTSPACE, - isActive = true, - recommendations = MediaTestHelper.getValidRecommendationList(icon), - ) - mediaFilterRepository.setRecommendation(mediaRecommendation) assertThat(hasActiveMediaOrRecommendation).isTrue() @@ -234,26 +219,42 @@ class MediaCarouselInteractorTest : SysuiTestCase() { @Test fun loadMediaFromRec() = testScope.runTest { - val isMediaFromRec by collectLastValue(underTest.isMediaFromRec) + val currentMedia by collectLastValue(underTest.currentMedia) val instanceId = InstanceId.fakeInstanceId(123) - val data = MediaData(active = true, instanceId = instanceId, packageName = PACKAGE_NAME) - - assertThat(isMediaFromRec).isFalse() + val data = + MediaData( + active = true, + instanceId = instanceId, + packageName = PACKAGE_NAME, + notificationKey = KEY + ) + val smartspaceLoadingModel = SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE) + val mediaLoadingModel = MediaDataLoadingModel.Loaded(instanceId) + mediaFilterRepository.setRecommendation(mediaRecommendation) + mediaFilterRepository.setRecommendationsLoadingState(smartspaceLoadingModel) mediaRecommendationsInteractor.switchToMediaControl(PACKAGE_NAME) mediaFilterRepository.addSelectedUserMediaEntry(data) - mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) + mediaFilterRepository.addMediaDataLoadingState(mediaLoadingModel) - assertThat(isMediaFromRec).isFalse() + assertThat(currentMedia) + .containsExactly(MediaCommonModel.MediaRecommendations(smartspaceLoadingModel)) + .inOrder() mediaFilterRepository.addSelectedUserMediaEntry(data.copy(isPlaying = true)) mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId)) - assertThat(isMediaFromRec).isTrue() + assertThat(currentMedia) + .containsExactly( + MediaCommonModel.MediaControl(mediaLoadingModel, isMediaFromRec = true), + MediaCommonModel.MediaRecommendations(smartspaceLoadingModel) + ) + .inOrder() } companion object { private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID" private const val PACKAGE_NAME = "com.android.example" + private const val KEY = "key" } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt index d9224d7e3421..bd3b77a678db 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaControlInteractorTest.kt @@ -27,12 +27,16 @@ import com.android.systemui.animation.ActivityTransitionAnimator import com.android.systemui.animation.DialogTransitionAnimator import com.android.systemui.animation.Expandable import com.android.systemui.bluetooth.mockBroadcastDialogController +import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope +import com.android.systemui.media.controls.data.repository.mediaDataRepository import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl +import com.android.systemui.media.controls.domain.pipeline.MediaDataProcessor import com.android.systemui.media.controls.domain.pipeline.interactor.MediaControlInteractor import com.android.systemui.media.controls.domain.pipeline.interactor.mediaControlInteractor import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter +import com.android.systemui.media.controls.domain.pipeline.mediaDataProcessor import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.media.controls.util.mediaInstanceId import com.android.systemui.media.mediaOutputDialogManager @@ -211,6 +215,21 @@ class MediaControlInteractorTest : SysuiTestCase() { ) } + @Test + fun removeMediaControl() { + val listener = mock<MediaDataProcessor.Listener>() + kosmos.mediaDataProcessor.addInternalListener(listener) + + var mediaData = MediaData(userId = USER_ID, instanceId = instanceId, artist = ARTIST) + kosmos.mediaDataRepository.addMediaEntry(KEY, mediaData) + + underTest.removeMediaControl(null, instanceId, 0L) + kosmos.fakeExecutor.advanceClockToNext() + kosmos.fakeExecutor.runAllReady() + + verify(listener).onMediaDataRemoved(eq(KEY), eq(true)) + } + companion object { private const val USER_ID = 0 private const val KEY = "key" diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt index d1e475f590dd..4226a9d89ad1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt @@ -92,13 +92,29 @@ class MediaCarouselViewModelTest : SysuiTestCase() { val instanceId1 = InstanceId.fakeInstanceId(123) val instanceId2 = InstanceId.fakeInstanceId(456) - loadMediaControl(KEY, instanceId1) - loadMediaControl(KEY_2, instanceId2) + loadMediaControl(KEY, instanceId1, isPlaying = true) + loadMediaControl(KEY_2, instanceId2, isPlaying = true) + loadMediaControl(KEY, instanceId1, isPlaying = false) - val firstMediaControl = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl - val secondMediaControl = sortedMedia?.get(1) as MediaCommonViewModel.MediaControl - assertThat(firstMediaControl.instanceId).isEqualTo(instanceId2) - assertThat(secondMediaControl.instanceId).isEqualTo(instanceId1) + var mediaControl2 = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl + var mediaControl1 = sortedMedia?.get(1) as MediaCommonViewModel.MediaControl + assertThat(mediaControl2.instanceId).isEqualTo(instanceId2) + assertThat(mediaControl1.instanceId).isEqualTo(instanceId1) + + loadMediaControl(KEY, instanceId1, isPlaying = true) + loadMediaControl(KEY_2, instanceId2, isPlaying = false) + + mediaControl2 = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl + mediaControl1 = sortedMedia?.get(1) as MediaCommonViewModel.MediaControl + assertThat(mediaControl2.instanceId).isEqualTo(instanceId2) + assertThat(mediaControl1.instanceId).isEqualTo(instanceId1) + + underTest.onAttached() + + mediaControl1 = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl + mediaControl2 = sortedMedia?.get(1) as MediaCommonViewModel.MediaControl + assertThat(mediaControl1.instanceId).isEqualTo(instanceId1) + assertThat(mediaControl2.instanceId).isEqualTo(instanceId2) } @Test @@ -147,6 +163,7 @@ class MediaCarouselViewModelTest : SysuiTestCase() { val mediaControl = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl assertThat(sortedMedia).hasSize(2) assertThat(mediaControl.instanceId).isEqualTo(instanceId) + assertThat(mediaControl.isMediaFromRec).isTrue() } private fun loadMediaControl(key: String, instanceId: InstanceId, isPlaying: Boolean = true) { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/CloseShadeRightAfterClickTestB339290820.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/CloseShadeRightAfterClickTestB339290820.kt new file mode 100644 index 000000000000..8d1aa73aa55c --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/external/CloseShadeRightAfterClickTestB339290820.kt @@ -0,0 +1,215 @@ +/* + * 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.qs.external + +import android.app.PendingIntent +import android.content.ComponentName +import android.content.Context +import android.content.ContextWrapper +import android.content.Intent +import android.content.ServiceConnection +import android.content.applicationContext +import android.content.packageManager +import android.os.Binder +import android.os.Handler +import android.os.RemoteException +import android.os.UserHandle +import android.platform.test.annotations.EnableFlags +import android.service.quicksettings.Tile +import android.testing.TestableContext +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX +import com.android.systemui.SysuiTestCase +import com.android.systemui.concurrency.fakeExecutor +import com.android.systemui.kosmos.testCase +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.tiles.impl.custom.packageManagerAdapterFacade +import com.android.systemui.qs.tiles.impl.custom.customTileSpec +import com.android.systemui.testKosmos +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.time.fakeSystemClock +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyString + +@RunWith(AndroidJUnit4::class) +@SmallTest +class CloseShadeRightAfterClickTestB339290820 : SysuiTestCase() { + + private val testableContext: TestableContext + private val bindDelayExecutor: FakeExecutor + private val kosmos = + testKosmos().apply { + testableContext = testCase.context + bindDelayExecutor = FakeExecutor(fakeSystemClock) + testableContext.setMockPackageManager(packageManager) + customTileSpec = TileSpec.create(testComponentName) + applicationContext = ContextWrapperDelayedBind(testableContext, bindDelayExecutor) + } + + @Before + fun setUp() { + kosmos.apply { + whenever(packageManager.getPackageUidAsUser(anyString(), anyInt(), anyInt())) + .thenReturn(Binder.getCallingUid()) + packageManagerAdapterFacade.setIsActive(true) + testableContext.addMockService(testComponentName, iQSTileService.asBinder()) + } + } + + @Test + @EnableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) + fun testStopListeningShortlyAfterClick_clickIsSent() { + with(kosmos) { + val tile = FakeCustomTileInterface(tileServices) + // Flush any bind from startup + FakeExecutor.exhaustExecutors(fakeExecutor, bindDelayExecutor) + + // Open QS + tile.setListening(true) + fakeExecutor.runAllReady() + tile.click() + fakeExecutor.runAllReady() + + // No clicks yet because the latch is preventing the bind + assertThat(iQSTileService.clicks).isEmpty() + + // Close QS + tile.setListening(false) + fakeExecutor.runAllReady() + // And finally bind + FakeExecutor.exhaustExecutors(fakeExecutor, bindDelayExecutor) + + assertThat(iQSTileService.clicks).containsExactly(tile.token) + } + } +} + +private val testComponentName = ComponentName("pkg", "srv") + +// This is a fake `CustomTile` that implements what we need for the test. Mainly setListening and +// click +private class FakeCustomTileInterface(tileServices: TileServices) : CustomTileInterface { + override val user: Int + get() = 0 + override val qsTile: Tile = Tile() + override val component: ComponentName = testComponentName + private var listening = false + private val serviceManager = tileServices.getTileWrapper(this) + private val serviceInterface = serviceManager.tileService + + val token = Binder() + + override fun getTileSpec(): String { + return CustomTile.toSpec(component) + } + + override fun refreshState() {} + + override fun updateTileState(tile: Tile, uid: Int) {} + + override fun onDialogShown() {} + + override fun onDialogHidden() {} + + override fun startActivityAndCollapse(pendingIntent: PendingIntent) {} + + override fun startUnlockAndRun() {} + + fun setListening(listening: Boolean) { + if (listening == this.listening) return + this.listening = listening + + try { + if (listening) { + if (!serviceManager.isActiveTile) { + serviceManager.setBindRequested(true) + serviceInterface.onStartListening() + } + } else { + serviceInterface.onStopListening() + serviceManager.setBindRequested(false) + } + } catch (e: RemoteException) { + // Called through wrapper, won't happen here. + } + } + + fun click() { + try { + if (serviceManager.isActiveTile) { + serviceManager.setBindRequested(true) + serviceInterface.onStartListening() + } + serviceInterface.onClick(token) + } catch (e: RemoteException) { + // Called through wrapper, won't happen here. + } + } +} + +private class ContextWrapperDelayedBind( + val context: Context, + val executor: FakeExecutor, +) : ContextWrapper(context) { + override fun bindServiceAsUser( + service: Intent, + conn: ServiceConnection, + flags: Int, + user: UserHandle + ): Boolean { + executor.execute { super.bindServiceAsUser(service, conn, flags, user) } + return true + } + + override fun bindServiceAsUser( + service: Intent, + conn: ServiceConnection, + flags: BindServiceFlags, + user: UserHandle + ): Boolean { + executor.execute { super.bindServiceAsUser(service, conn, flags, user) } + return true + } + + override fun bindServiceAsUser( + service: Intent?, + conn: ServiceConnection?, + flags: Int, + handler: Handler?, + user: UserHandle? + ): Boolean { + executor.execute { super.bindServiceAsUser(service, conn, flags, handler, user) } + return true + } + + override fun bindServiceAsUser( + service: Intent, + conn: ServiceConnection, + flags: BindServiceFlags, + handler: Handler, + user: UserHandle + ): Boolean { + executor.execute { super.bindServiceAsUser(service, conn, flags, handler, user) } + return true + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileRepositoryTest.kt index da60c18dcfd7..dfc004a126bd 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/data/repository/CustomTileRepositoryTest.kt @@ -30,10 +30,10 @@ import com.android.systemui.qs.external.TileServiceKey import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.impl.custom.TileSubject.Companion.assertThat import com.android.systemui.qs.tiles.impl.custom.commons.copy +import com.android.systemui.qs.tiles.impl.custom.customTileSpec import com.android.systemui.qs.tiles.impl.custom.customTileStatePersister import com.android.systemui.qs.tiles.impl.custom.data.entity.CustomTileDefaults import com.android.systemui.qs.tiles.impl.custom.packageManagerAdapterFacade -import com.android.systemui.qs.tiles.impl.custom.tileSpec import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first @@ -47,11 +47,11 @@ import org.junit.runner.RunWith @OptIn(ExperimentalCoroutinesApi::class) class CustomTileRepositoryTest : SysuiTestCase() { - private val kosmos = Kosmos().apply { tileSpec = TileSpec.create(TEST_COMPONENT) } + private val kosmos = Kosmos().apply { customTileSpec = TileSpec.create(TEST_COMPONENT) } private val underTest: CustomTileRepository = with(kosmos) { CustomTileRepositoryImpl( - tileSpec, + customTileSpec, customTileStatePersister, packageManagerAdapterFacade.packageManagerAdapter, testScope.testScheduler, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractorTest.kt index a5c554406848..a29289a7409a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileDataInteractorTest.kt @@ -38,8 +38,8 @@ import com.android.systemui.qs.tiles.impl.custom.customTileInteractor import com.android.systemui.qs.tiles.impl.custom.customTilePackagesUpdatesRepository import com.android.systemui.qs.tiles.impl.custom.customTileRepository import com.android.systemui.qs.tiles.impl.custom.customTileServiceInteractor +import com.android.systemui.qs.tiles.impl.custom.customTileSpec import com.android.systemui.qs.tiles.impl.custom.data.entity.CustomTileDefaults -import com.android.systemui.qs.tiles.impl.custom.tileSpec import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.user.data.repository.userRepository @@ -60,12 +60,12 @@ class CustomTileDataInteractorTest : SysuiTestCase() { private val kosmos = testKosmos().apply { componentName = TEST_COMPONENT - tileSpec = TileSpec.create(componentName) + customTileSpec = TileSpec.create(componentName) } private val underTest = with(kosmos) { CustomTileDataInteractor( - tileSpec = tileSpec, + tileSpec = customTileSpec, defaultsRepository = customTileDefaultsRepository, serviceInteractor = customTileServiceInteractor, customTileInteractor = customTileInteractor, @@ -180,7 +180,7 @@ class CustomTileDataInteractorTest : SysuiTestCase() { setup() customTileDefaultsRepository.putDefaults( TEST_USER_1.userHandle, - tileSpec.componentName, + customTileSpec.componentName, CustomTileDefaults.Result(TEST_TILE.icon, TEST_TILE.label), ) @@ -198,7 +198,7 @@ class CustomTileDataInteractorTest : SysuiTestCase() { setup() customTileDefaultsRepository.putDefaults( TEST_USER_1.userHandle, - tileSpec.componentName, + customTileSpec.componentName, CustomTileDefaults.Error, ) @@ -216,7 +216,7 @@ class CustomTileDataInteractorTest : SysuiTestCase() { setup() customTileDefaultsRepository.putDefaults( TEST_USER_2.userHandle, - tileSpec.componentName, + customTileSpec.componentName, CustomTileDefaults.Error, ) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileInteractorTest.kt index 9546a32e2a06..33299d9ce74c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileInteractorTest.kt @@ -31,9 +31,9 @@ import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.impl.custom.TileSubject.Companion.assertThat import com.android.systemui.qs.tiles.impl.custom.customTileDefaultsRepository import com.android.systemui.qs.tiles.impl.custom.customTileRepository +import com.android.systemui.qs.tiles.impl.custom.customTileSpec import com.android.systemui.qs.tiles.impl.custom.customTileStatePersister import com.android.systemui.qs.tiles.impl.custom.data.entity.CustomTileDefaults -import com.android.systemui.qs.tiles.impl.custom.tileSpec import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -50,12 +50,12 @@ import org.junit.runner.RunWith @OptIn(ExperimentalCoroutinesApi::class) class CustomTileInteractorTest : SysuiTestCase() { - private val kosmos = testKosmos().apply { tileSpec = TileSpec.create(TEST_COMPONENT) } + private val kosmos = testKosmos().apply { customTileSpec = TileSpec.create(TEST_COMPONENT) } private val underTest: CustomTileInteractor = with(kosmos) { CustomTileInteractor( - tileSpec = tileSpec, + tileSpec = customTileSpec, defaultsRepository = customTileDefaultsRepository, customTileRepository = customTileRepository, tileScope = testScope.backgroundScope, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileMapperTest.kt index a2127a4717ce..3972938d7b1b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileMapperTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileMapperTest.kt @@ -33,9 +33,9 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject.Companion.assertThat import com.android.systemui.qs.tiles.impl.custom.customTileQsTileConfig +import com.android.systemui.qs.tiles.impl.custom.customTileSpec import com.android.systemui.qs.tiles.impl.custom.domain.CustomTileMapper import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel -import com.android.systemui.qs.tiles.impl.custom.tileSpec import com.android.systemui.qs.tiles.viewmodel.QSTileState import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any @@ -51,7 +51,8 @@ import org.junit.runner.RunWith class CustomTileMapperTest : SysuiTestCase() { private val uriGrantsManager: IUriGrantsManager = mock {} - private val kosmos = testKosmos().apply { tileSpec = TileSpec.Companion.create(TEST_COMPONENT) } + private val kosmos = + testKosmos().apply { customTileSpec = TileSpec.Companion.create(TEST_COMPONENT) } private val underTest by lazy { CustomTileMapper( context = mock { whenever(createContextAsUser(any(), any())).thenReturn(context) }, @@ -202,7 +203,7 @@ class CustomTileMapperTest : SysuiTestCase() { ) = CustomTileDataModel( UserHandle.of(1), - tileSpec.componentName, + customTileSpec.componentName, Tile().apply { state = tileState label = "test label" diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractorTest.kt index c709f16c3213..72e5766e409a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/custom/domain/interactor/CustomTileUserActionInteractorTest.kt @@ -44,9 +44,9 @@ import com.android.systemui.qs.tiles.base.actions.pendingIntentInputs import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.click import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.longClick import com.android.systemui.qs.tiles.impl.custom.customTileServiceInteractor +import com.android.systemui.qs.tiles.impl.custom.customTileSpec import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel import com.android.systemui.qs.tiles.impl.custom.qsTileLogger -import com.android.systemui.qs.tiles.impl.custom.tileSpec import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.fakeUserRepository import com.android.systemui.util.mockito.any @@ -68,7 +68,7 @@ class CustomTileUserActionInteractorTest : SysuiTestCase() { private val kosmos = testKosmos().apply { componentName = TEST_COMPONENT - tileSpec = TileSpec.create(componentName) + customTileSpec = TileSpec.create(componentName) testCase = this@CustomTileUserActionInteractorTest } @@ -79,7 +79,7 @@ class CustomTileUserActionInteractorTest : SysuiTestCase() { mock { whenever(packageManager).thenReturn(packageManagerFacade.packageManager) }, - tileSpec = tileSpec, + tileSpec = customTileSpec, qsTileLogger = qsTileLogger, windowManager = windowManagerFacade.windowManager, displayTracker = mock {}, @@ -227,7 +227,7 @@ class CustomTileUserActionInteractorTest : SysuiTestCase() { private fun pendingIntent(): PendingIntent = mock { whenever(isActivity).thenReturn(true) } private fun Kosmos.customTileModel( - componentName: ComponentName = tileSpec.componentName, + componentName: ComponentName = customTileSpec.componentName, activityLaunchForClick: PendingIntent? = null, tileState: Int = 111, ) = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt index 179ba42cc772..0b55befce932 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt @@ -35,7 +35,10 @@ import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope +import com.android.systemui.media.controls.data.repository.mediaFilterRepository import com.android.systemui.media.controls.domain.pipeline.MediaDataManager +import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor +import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter @@ -100,7 +103,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { footerActionsViewModelFactory = footerActionsViewModelFactory, footerActionsController = footerActionsController, sceneBackInteractor = sceneBackInteractor, - mediaDataManager = mediaDataManager, + mediaCarouselInteractor = kosmos.mediaCarouselInteractor, ) } @@ -236,20 +239,34 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() { } @Test - fun hasMedia_mediaVisible() { + fun addAndRemoveMedia_mediaVisibilityIsUpdated() = testScope.runTest { - whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(true) + kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false) + val isMediaVisible by collectLastValue(underTest.isMediaVisible) + val userMedia = MediaData(active = true) - assertThat(underTest.isMediaVisible()).isTrue() + assertThat(isMediaVisible).isFalse() + + kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia) + + assertThat(isMediaVisible).isTrue() + + kosmos.mediaFilterRepository.removeSelectedUserMediaEntry(userMedia.instanceId) + + assertThat(isMediaVisible).isFalse() } - } @Test - fun doesNotHaveMedia_mediaNotVisible() { + fun addInactiveMedia_mediaVisibilityIsUpdated() = testScope.runTest { - whenever(mediaDataManager.hasAnyMediaOrRecommendation()).thenReturn(false) + kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false) + val isMediaVisible by collectLastValue(underTest.isMediaVisible) + val userMedia = MediaData(active = false) + + assertThat(isMediaVisible).isFalse() - assertThat(underTest.isMediaVisible()).isFalse() + kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia) + + assertThat(isMediaVisible).isTrue() } - } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt index 4cb8bf84967b..9e7e766cb820 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt @@ -52,6 +52,7 @@ import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel import com.android.systemui.kosmos.testScope import com.android.systemui.media.controls.domain.pipeline.MediaDataManager +import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAsleepForTest import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.powerInteractor @@ -209,7 +210,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() { qsSceneAdapter = qsFlexiglassAdapter, notifications = kosmos.notificationsPlaceholderViewModel, brightnessMirrorViewModel = kosmos.brightnessMirrorViewModel, - mediaDataManager = mediaDataManager, + mediaCarouselInteractor = kosmos.mediaCarouselInteractor, shadeInteractor = kosmos.shadeInteractor, footerActionsController = kosmos.footerActionsController, footerActionsViewModelFactory = kosmos.footerActionsViewModelFactory, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt index 93465c804d0e..677477df8ea1 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt @@ -437,12 +437,12 @@ class SceneContainerStartableTest : SysuiTestCase() { runCurrent() assertThat( sysUiState.flags and - QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED != 0 + QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED != 0L ) .isTrue() assertThat( sysUiState.flags and - QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING != 0 + QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING != 0L ) .isFalse() @@ -450,12 +450,12 @@ class SceneContainerStartableTest : SysuiTestCase() { runCurrent() assertThat( sysUiState.flags and - QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED != 0 + QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED != 0L ) .isFalse() assertThat( sysUiState.flags and - QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING != 0 + QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING != 0L ) .isTrue() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt index a2ffe7008009..545a0c70719f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModelTest.kt @@ -25,7 +25,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.kosmos.testScope -import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade +import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.domain.interactor.shadeInteractor import com.android.systemui.shade.shared.model.ShadeMode @@ -67,7 +67,7 @@ class GoneSceneViewModelTest : SysuiTestCase() { runCurrent() assertThat(destinationScenes?.get(Swipe(SwipeDirection.Down))?.transitionKey) - .isEqualTo(GoneToSplitShade) + .isEqualTo(ToSplitShade) } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt index 243921753f22..482dc5d992f0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt @@ -32,14 +32,17 @@ import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus import com.android.systemui.kosmos.testScope +import com.android.systemui.media.controls.data.repository.mediaFilterRepository import com.android.systemui.media.controls.domain.pipeline.MediaDataManager +import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor +import com.android.systemui.media.controls.shared.model.MediaData import com.android.systemui.qs.footerActionsController import com.android.systemui.qs.footerActionsViewModelFactory import com.android.systemui.qs.ui.adapter.FakeQSSceneAdapter import com.android.systemui.res.R import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes -import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade +import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade import com.android.systemui.settings.brightness.ui.viewmodel.brightnessMirrorViewModel import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.domain.interactor.shadeInteractor @@ -50,7 +53,6 @@ import com.android.systemui.testKosmos import com.android.systemui.unfold.domain.interactor.unfoldTransitionInteractor import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import java.util.Locale import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -94,7 +96,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() { qsSceneAdapter = qsSceneAdapter, notifications = kosmos.notificationsPlaceholderViewModel, brightnessMirrorViewModel = kosmos.brightnessMirrorViewModel, - mediaDataManager = mediaDataManager, + mediaCarouselInteractor = kosmos.mediaCarouselInteractor, shadeInteractor = kosmos.shadeInteractor, footerActionsViewModelFactory = kosmos.footerActionsViewModelFactory, footerActionsController = kosmos.footerActionsController, @@ -167,11 +169,11 @@ class ShadeSceneViewModelTest : SysuiTestCase() { runCurrent() assertThat(destinationScenes?.get(Swipe(SwipeDirection.Up))?.transitionKey) - .isEqualTo(GoneToSplitShade) + .isEqualTo(ToSplitShade) } @Test - fun upTransitionKey_splitShadeDisabled_isNull() = + fun upTransitionKey_splitShadeDisable_isNull() = testScope.runTest { val destinationScenes by collectLastValue(underTest.destinationScenes) shadeRepository.setShadeMode(ShadeMode.Single) @@ -222,19 +224,20 @@ class ShadeSceneViewModelTest : SysuiTestCase() { } @Test - fun hasActiveMedia_mediaVisible() = + fun addAndRemoveMedia_mediaVisibilityisUpdated() = testScope.runTest { - whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(true) + val isMediaVisible by collectLastValue(underTest.isMediaVisible) + val userMedia = MediaData(active = true) - assertThat(underTest.isMediaVisible()).isTrue() - } + assertThat(isMediaVisible).isFalse() - @Test - fun doesNotHaveActiveMedia_mediaNotVisible() = - testScope.runTest { - whenever(mediaDataManager.hasActiveMediaOrRecommendation()).thenReturn(false) + kosmos.mediaFilterRepository.addSelectedUserMediaEntry(userMedia) + + assertThat(isMediaVisible).isTrue() + + kosmos.mediaFilterRepository.removeSelectedUserMediaEntry(userMedia.instanceId) - assertThat(underTest.isMediaVisible()).isFalse() + assertThat(isMediaVisible).isFalse() } @Test diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt new file mode 100644 index 000000000000..8cb811de851b --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar + +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.service.notification.NotificationListenerService +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags +import com.android.systemui.SysuiTestCase +import com.android.systemui.dump.dumpManager +import com.android.systemui.media.controls.domain.pipeline.MediaDataManager +import com.android.systemui.statusbar.notification.collection.NotificationEntry +import com.android.systemui.statusbar.notification.collection.mockNotifCollection +import com.android.systemui.statusbar.notification.collection.notifPipeline +import com.android.systemui.statusbar.notification.collection.render.notificationVisibilityProvider +import com.android.systemui.testKosmos +import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.time.FakeSystemClock +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.never +import org.mockito.Mockito.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +class NotificationMediaManagerTest : SysuiTestCase() { + + private val KEY = "KEY" + + private val kosmos = testKosmos() + private val visibilityProvider = kosmos.notificationVisibilityProvider + private val notifPipeline = kosmos.notifPipeline + private val notifCollection = kosmos.mockNotifCollection + private val dumpManager = kosmos.dumpManager + private val mediaDataManager = mock<MediaDataManager>() + private val backgroundExecutor = FakeExecutor(FakeSystemClock()) + + private var listenerCaptor = argumentCaptor<MediaDataManager.Listener>() + + private lateinit var notificationMediaManager: NotificationMediaManager + + @Before + fun setup() { + notificationMediaManager = + NotificationMediaManager( + context, + visibilityProvider, + notifPipeline, + notifCollection, + mediaDataManager, + dumpManager, + backgroundExecutor, + ) + + verify(mediaDataManager).addListener(listenerCaptor.capture()) + } + + @Test + @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_USER_INITIATED_DISMISS) + fun mediaDataRemoved_userInitiated_dismissNotif() { + val notifEntryCaptor = argumentCaptor<NotificationEntry>() + val notifEntry = mock<NotificationEntry>() + whenever(notifEntry.key).thenReturn(KEY) + whenever(notifEntry.ranking).thenReturn(NotificationListenerService.Ranking()) + whenever(notifPipeline.allNotifs).thenReturn(listOf(notifEntry)) + + listenerCaptor.lastValue.onMediaDataRemoved(KEY, true) + + verify(notifCollection).dismissNotification(notifEntryCaptor.capture(), any()) + assertThat(notifEntryCaptor.lastValue.key).isEqualTo(KEY) + } + + @Test + @EnableFlags(Flags.FLAG_MEDIA_CONTROLS_USER_INITIATED_DISMISS) + fun mediaDataRemoved_notUserInitiated_doesNotDismissNotif() { + listenerCaptor.lastValue.onMediaDataRemoved(KEY, false) + + verify(notifCollection, never()).dismissNotification(any(), any()) + } + + @Test + @DisableFlags(Flags.FLAG_MEDIA_CONTROLS_USER_INITIATED_DISMISS) + fun mediaDataRemoved_notUserInitiated_flagOff_dismissNotif() { + val notifEntryCaptor = argumentCaptor<NotificationEntry>() + val notifEntry = mock<NotificationEntry>() + whenever(notifEntry.key).thenReturn(KEY) + whenever(notifEntry.ranking).thenReturn(NotificationListenerService.Ranking()) + whenever(notifPipeline.allNotifs).thenReturn(listOf(notifEntry)) + + listenerCaptor.lastValue.onMediaDataRemoved(KEY, false) + + verify(notifCollection).dismissNotification(notifEntryCaptor.capture(), any()) + assertThat(notifEntryCaptor.lastValue.key).isEqualTo(KEY) + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt index 1f0812da9fe9..ee9fd3494d96 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModelTest.kt @@ -44,13 +44,4 @@ class NotificationsPlaceholderViewModelTest : SysuiTestCase() { collectLastValue(kosmos.notificationStackAppearanceInteractor.shadeScrimBounds) assertThat(stackBounds).isEqualTo(bounds) } - - @Test - fun onStackBoundsChanged() = - kosmos.testScope.runTest { - underTest.onStackBoundsChanged(top = 5f, bottom = 500f) - assertThat(kosmos.notificationStackAppearanceInteractor.stackTop.value).isEqualTo(5f) - assertThat(kosmos.notificationStackAppearanceInteractor.stackBottom.value) - .isEqualTo(500f) - } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt index f2ce745ed293..da17366a8416 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt @@ -660,9 +660,6 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S overrideResource(R.bool.config_use_split_notification_shade, false) configurationRepository.onAnyConfigurationChange() - keyguardInteractor.setNotificationContainerBounds( - NotificationContainerBounds(top = 1f, bottom = 2f) - ) assertThat(maxNotifications).isEqualTo(10) @@ -691,9 +688,6 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S overrideResource(R.bool.config_use_split_notification_shade, false) configurationRepository.onAnyConfigurationChange() - keyguardInteractor.setNotificationContainerBounds( - NotificationContainerBounds(top = 1f, bottom = 2f) - ) assertThat(maxNotifications).isEqualTo(10) @@ -728,9 +722,6 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S overrideResource(R.bool.config_use_split_notification_shade, false) configurationRepository.onAnyConfigurationChange() - keyguardInteractor.setNotificationContainerBounds( - NotificationContainerBounds(top = 1f, bottom = 2f) - ) // -1 means No Limit assertThat(maxNotifications).isEqualTo(-1) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt index 27a813fb149e..fdea5a4bd765 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelTest.kt @@ -32,7 +32,7 @@ import com.android.systemui.testKosmos import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq import com.android.systemui.volume.panel.ui.VolumePanelUiEvent -import com.android.systemui.volume.panel.volumePanelViewModel +import com.android.systemui.volume.panel.ui.viewmodel.volumePanelViewModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorImplTest.kt index 6256eece65dd..ab184abdc963 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorImplTest.kt @@ -22,14 +22,14 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope -import com.android.systemui.volume.panel.availableCriteria -import com.android.systemui.volume.panel.criteriaByKey -import com.android.systemui.volume.panel.defaultCriteria +import com.android.systemui.volume.panel.domain.availableCriteria +import com.android.systemui.volume.panel.domain.defaultCriteria import com.android.systemui.volume.panel.domain.model.ComponentModel -import com.android.systemui.volume.panel.enabledComponents +import com.android.systemui.volume.panel.domain.unavailableCriteria import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey -import com.android.systemui.volume.panel.unavailableCriteria +import com.android.systemui.volume.panel.ui.composable.enabledComponents import com.google.common.truth.Truth.assertThat +import javax.inject.Provider import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith @@ -47,7 +47,7 @@ class ComponentsInteractorImplTest : SysuiTestCase() { with(kosmos) { ComponentsInteractorImpl( enabledComponents, - defaultCriteria, + { defaultCriteria }, testScope.backgroundScope, criteriaByKey, ) @@ -66,9 +66,9 @@ class ComponentsInteractorImplTest : SysuiTestCase() { ) criteriaByKey = mapOf( - BOTTOM_BAR to availableCriteria, - COMPONENT_1 to unavailableCriteria, - COMPONENT_2 to availableCriteria, + BOTTOM_BAR to Provider { availableCriteria }, + COMPONENT_1 to Provider { unavailableCriteria }, + COMPONENT_2 to Provider { availableCriteria }, ) initUnderTest() @@ -96,8 +96,8 @@ class ComponentsInteractorImplTest : SysuiTestCase() { ) criteriaByKey = mapOf( - BOTTOM_BAR to availableCriteria, - COMPONENT_2 to availableCriteria, + BOTTOM_BAR to Provider { availableCriteria }, + COMPONENT_2 to Provider { availableCriteria }, ) defaultCriteria = unavailableCriteria initUnderTest() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryTest.kt index 3dbf23e3dc58..e3dc55203286 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryTest.kt @@ -20,9 +20,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.testKosmos -import com.android.systemui.volume.panel.componentByKey -import com.android.systemui.volume.panel.mockVolumePanelUiComponentProvider import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey +import com.android.systemui.volume.panel.shared.model.mockVolumePanelUiComponentProvider import com.google.common.truth.Truth import org.junit.Test import org.junit.runner.RunWith diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt index 82ce6d785e90..b37184dc941c 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/DefaultComponentsLayoutManagerTest.kt @@ -20,8 +20,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.testKosmos -import com.android.systemui.volume.panel.mockVolumePanelUiComponent import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey +import com.android.systemui.volume.panel.shared.model.mockVolumePanelUiComponent import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager import com.android.systemui.volume.panel.ui.layout.DefaultComponentsLayoutManager import com.google.common.truth.Truth diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt index 4e0685556145..f6ada4c166dc 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelTest.kt @@ -28,15 +28,15 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.policy.fakeConfigurationController import com.android.systemui.testKosmos -import com.android.systemui.volume.panel.componentByKey -import com.android.systemui.volume.panel.componentsLayoutManager -import com.android.systemui.volume.panel.criteriaByKey -import com.android.systemui.volume.panel.mockVolumePanelUiComponentProvider +import com.android.systemui.volume.panel.domain.interactor.criteriaByKey +import com.android.systemui.volume.panel.domain.unavailableCriteria import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey +import com.android.systemui.volume.panel.shared.model.mockVolumePanelUiComponentProvider +import com.android.systemui.volume.panel.ui.composable.componentByKey import com.android.systemui.volume.panel.ui.layout.DefaultComponentsLayoutManager -import com.android.systemui.volume.panel.unavailableCriteria -import com.android.systemui.volume.panel.volumePanelViewModel +import com.android.systemui.volume.panel.ui.layout.componentsLayoutManager import com.google.common.truth.Truth.assertThat +import javax.inject.Provider import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest @@ -95,7 +95,7 @@ class VolumePanelViewModelTest : SysuiTestCase() { COMPONENT_2 to mockVolumePanelUiComponentProvider, BOTTOM_BAR to mockVolumePanelUiComponentProvider, ) - criteriaByKey = mapOf(COMPONENT_2 to unavailableCriteria) + criteriaByKey = mapOf(COMPONENT_2 to Provider { unavailableCriteria }) }) { testScope.runTest { val componentsLayout by collectLastValue(underTest.componentsLayout) diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt index 79bf5f19997b..629c96c0ef44 100644 --- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt +++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockProviderPlugin.kt @@ -109,6 +109,12 @@ data class ClockMessageBuffers( val largeClockMessageBuffer: MessageBuffer, ) +data class AodClockBurnInModel( + val scale: Float, + val translationX: Float, + val translationY: Float, +) + /** Specifies layout information for the */ interface ClockFaceLayout { /** All clock views to add to the root constraint layout before applying constraints. */ @@ -118,6 +124,8 @@ interface ClockFaceLayout { fun applyConstraints(constraints: ConstraintSet): ConstraintSet fun applyPreviewConstraints(constraints: ConstraintSet): ConstraintSet + + fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel) } /** A ClockFaceLayout that applies the default lockscreen layout to a single view */ @@ -137,6 +145,10 @@ class DefaultClockFaceLayout(val view: View) : ClockFaceLayout { override fun applyPreviewConstraints(constraints: ConstraintSet): ConstraintSet { return constraints } + + override fun applyAodBurnIn(aodBurnInModel: AodClockBurnInModel) { + // Default clock doesn't need detailed control of view + } } /** Events that should call when various rendering parameters change */ diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml index b4b2a1935393..efc750b53cc3 100644 --- a/packages/SystemUI/res-keyguard/values-hr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml @@ -61,7 +61,7 @@ <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Lice nije prepoznato"</string> <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Pokušajte ponovno ili unesite PIN"</string> <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Pokušajte ponovno ili unesite zaporku"</string> - <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Pokušajte ponovno ili izradite uzorak"</string> + <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"Pokušajte ponovno ili nacrtajte uzorak"</string> <string name="kg_bio_too_many_attempts_pin" msgid="5850845723433047605">"PIN je obavezan nakon previše pokušaja"</string> <string name="kg_bio_too_many_attempts_password" msgid="5551690347827728042">"Zaporka je obavezna nakon previše pokušaja"</string> <string name="kg_bio_too_many_attempts_pattern" msgid="736884689355181602">"Uzorak je obavezan nakon previše pokušaja"</string> diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml index c4fc5f7e0802..2bace4a702eb 100644 --- a/packages/SystemUI/res-keyguard/values-my/strings.xml +++ b/packages/SystemUI/res-keyguard/values-my/strings.xml @@ -116,7 +116,7 @@ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"ထပ်ဆောင်း လုံခြုံရေးအတွက် စကားဝှက် လိုအပ်သည်"</string> <string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"စက်ပစ္စည်းကို စီမံခန့်ခွဲသူက လော့ခ်ချထားပါသည်"</string> <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"စက်ပစ္စည်းကို ကိုယ်တိုင်ကိုယ်ကျ လော့ခ်ချထားခဲ့သည်"</string> - <string name="kg_face_not_recognized" msgid="7903950626744419160">"မသိ"</string> + <string name="kg_face_not_recognized" msgid="7903950626744419160">"မသိပါ"</string> <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"‘မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း’ သုံးရန် ‘ဆက်တင်များ’ တွင်ကင်မရာသုံးခွင့်ကိုဖွင့်ပါ"</string> <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{ဆင်းမ်ပင်နံပါတ် ထည့်သွင်းပါ။ သင့်စက်ကို လော့ခ်ဖွင့်ရန် မိုဘိုင်းဖုန်းကုမ္ပဏီသို့ မဆက်သွယ်မီ # ကြိမ် ကြိုးစားခွင့်ရှိသေးသည်။}other{ဆင်းမ်ပင်နံပါတ် ထည့်သွင်းပါ။ သင့်တွင် # ကြိမ် ကြိုးစားခွင့်ရှိသေးသည်။}}"</string> <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{ဆင်းမ်ကတ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် PUK ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကတ် အပြီးပိတ်မသွားမီ သင့်တွင် # ကြိမ် ကြိုးစားခွင့်ရှိသေးသည်။ အသေးစိတ်အတွက် မိုဘိုင်းဖုန်းကုမ္ပဏီကို ဆက်သွယ်ပါ။}other{ဆင်းမ်ကတ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် PUK ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကတ် အပြီးပိတ်မသွားမီ သင့်တွင် # ကြိမ် ကြိုးစားခွင့်ရှိသေးသည်။ အသေးစိတ်အတွက် မိုဘိုင်းဖုန်းကုမ္ပဏီကို ဆက်သွယ်ပါ။}}"</string> diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml index 2bfdef6ca182..224f1aeef05d 100644 --- a/packages/SystemUI/res-keyguard/values-ne/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml @@ -58,7 +58,7 @@ <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"PIN मिलेन। फेरि प्रयास गर्नुहोस्।"</string> <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"वा फिंगरप्रिन्ट प्रयोग गरी अनलक गर्नुहोस्"</string> <string name="kg_fp_not_recognized" msgid="5183108260932029241">"फिंगरप्रिन्ट मिलेन"</string> - <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"अनुहार पहिचान गर्न सकिएन"</string> + <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"अनुहार मिलेन"</string> <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"फेरि प्रयास गर्नुहोस् वा PIN हाल्नुहोस्"</string> <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"फेरि प्रयास गर्नुहोस् वा पासवर्ड हाल्नुहोस्"</string> <string name="kg_bio_try_again_or_pattern" msgid="4867893307468801501">"फेरि प्रयास गर्नुहोस् वा प्याटर्न हाल्नुहोस्"</string> diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml index 9b0647afb614..4dffd971dd27 100644 --- a/packages/SystemUI/res-keyguard/values-sk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml @@ -57,7 +57,7 @@ <string name="kg_wrong_pin" msgid="4160978845968732624">"Nesprávny kód PIN"</string> <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"Nesprávny kód PIN. Zopakujte."</string> <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"Alebo odomknite odtlačkom prsta"</string> - <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Nerozpoz. odtlačok prsta"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"Odtlačok prsta nebol rozpoznaný"</string> <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"Tvár nebola rozpoznaná"</string> <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"Skúste to znova alebo zadajte PIN"</string> <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"Skúste to znova alebo zadajte heslo"</string> diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml index 60f60c4c1879..b73372f72929 100644 --- a/packages/SystemUI/res-keyguard/values-ta/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml @@ -57,7 +57,7 @@ <string name="kg_wrong_pin" msgid="4160978845968732624">"தவறான பின்"</string> <string name="kg_wrong_pin_try_again" msgid="3129729383303430190">"தவறு. மீண்டும் முயலவும்."</string> <string name="kg_wrong_input_try_fp_suggestion" msgid="3143861542242024833">"இல்லையெனில் கைரேகை மூலம் அன்லாக் செய்யவும்"</string> - <string name="kg_fp_not_recognized" msgid="5183108260932029241">"கைரேகை அடையாளம் இல்லை"</string> + <string name="kg_fp_not_recognized" msgid="5183108260932029241">"கைரேகையை அடையாளம் காண முடியவில்லை"</string> <string name="bouncer_face_not_recognized" msgid="1666128054475597485">"முகம் கண்டறிய முடியவில்லை"</string> <string name="kg_bio_try_again_or_pin" msgid="4752168242723808390">"மீண்டும் முயலவும் அல்லது பின்னை உள்ளிடவும்"</string> <string name="kg_bio_try_again_or_password" msgid="1473132729225398039">"மீண்டும் முயலவும் அல்லது கடவுச்சொல்லை உள்ளிடவும்"</string> diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml index fa2a234d4368..fcb3a3ec8edc 100644 --- a/packages/SystemUI/res-keyguard/values-ur/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml @@ -116,7 +116,7 @@ <string name="kg_prompt_added_security_password" msgid="6053156069765029006">"اضافی سیکیورٹی کیلئے پاس ورڈ درکار ہے"</string> <string name="kg_prompt_reason_device_admin" msgid="6961159596224055685">"آلہ منتظم کی جانب سے مقفل ہے"</string> <string name="kg_prompt_reason_user_request" msgid="6015774877733717904">"آلہ کو دستی طور پر مقفل کیا گیا تھا"</string> - <string name="kg_face_not_recognized" msgid="7903950626744419160">"تسلیم شدہ نہیں ہے"</string> + <string name="kg_face_not_recognized" msgid="7903950626744419160">"شناخت نہیں ہو سکی"</string> <string name="kg_face_sensor_privacy_enabled" msgid="939511161763558512">"فیس اَنلاک استعمال کرنے کیلئے، ترتیبات میں کیمرا تک رسائی کو آن کریں"</string> <string name="kg_password_default_pin_message" msgid="1434544655827987873">"{count,plural, =1{SIM کا PIN درج کریں۔ اس سے پہلے کہ آپ اپنا آلہ غیر مقفل کرنے کیلئے لازمی طور پر اپنے کیریئر سے رابطہ کریں آپ کے پاس # کوشش بچی ہے۔}other{SIM کا PIN درج کریں۔ آپ کے پاس # کوششیں بچی ہیں۔}}"</string> <string name="kg_password_default_puk_message" msgid="1025139786449741950">"{count,plural, =1{SIM اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ SIM کے مستقل طور پر ناقابل استعمال ہونے سے پہلے آپ کے پاس # کوشش بچی ہے۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔}other{SIM اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ SIM کے مستقل طور پر ناقابل استعمال ہونے سے پہلے آپ کے پاس # کوششیں بچی ہیں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔}}"</string> diff --git a/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml b/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml index cf7a730dc379..a30a12221105 100644 --- a/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml +++ b/packages/SystemUI/res/drawable/qs_tile_background_flagged.xml @@ -13,12 +13,16 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<layer-list xmlns:android="http://schemas.android.com/apk/res/android" > - <!-- Since this layer list has just one layer, we can remove it and replace with the inner - layer drawable. However this should only be done when the flag +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="@color/qs_tile_ripple_color"> + <!-- We don't really use the ripple effect here, but changing it to LayerDrawable causes + performance regression, see: b/339412453. + Since this ripple has just one layer inside, we can try to remove that extra "background" + layer. However this should only be done when the flag com.android.systemui.qs_tile_focus_state has completed all its stages and this drawable fully replaces the previous one to ensure consistency with code sections searching for - specific ids in drawable hierarchy --> + specific ids in drawable hierarchy + --> <item android:id="@id/background"> <layer-list> @@ -48,4 +52,4 @@ </item> </layer-list> </item> -</layer-list>
\ No newline at end of file +</ripple>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml index f644584f747a..5755dcd70a82 100644 --- a/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml +++ b/packages/SystemUI/res/layout-land/biometric_prompt_constraint_layout.xml @@ -47,6 +47,7 @@ android:layout_height="match_parent"> android:layout_gravity="center" android:contentDescription="@null" android:scaleType="fitXY" + android:importantForAccessibility="no" app:layout_constraintBottom_toBottomOf="@+id/biometric_icon" app:layout_constraintEnd_toEndOf="@+id/biometric_icon" app:layout_constraintStart_toStartOf="@+id/biometric_icon" diff --git a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml index 46b8e4665a22..05f6faea464e 100644 --- a/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml +++ b/packages/SystemUI/res/layout-sw600dp/biometric_prompt_constraint_layout.xml @@ -229,6 +229,7 @@ android:layout_gravity="center" android:contentDescription="@null" android:scaleType="fitXY" + android:importantForAccessibility="no" app:layout_constraintBottom_toBottomOf="@+id/biometric_icon" app:layout_constraintEnd_toEndOf="@+id/biometric_icon" app:layout_constraintStart_toStartOf="@+id/biometric_icon" diff --git a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml index d51fe5849133..fa4d9a868fd7 100644 --- a/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml +++ b/packages/SystemUI/res/layout/biometric_prompt_constraint_layout.xml @@ -222,6 +222,7 @@ android:layout_gravity="center" android:contentDescription="@null" android:scaleType="fitXY" + android:importantForAccessibility="no" app:layout_constraintBottom_toBottomOf="@+id/biometric_icon" app:layout_constraintEnd_toEndOf="@+id/biometric_icon" app:layout_constraintStart_toStartOf="@+id/biometric_icon" diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml index 76d10ccb8a25..a598007833d7 100644 --- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml +++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml @@ -136,7 +136,8 @@ <TextView android:id="@+id/bluetooth_auto_on_toggle_title" android:layout_width="0dp" - android:layout_height="68dp" + android:layout_height="wrap_content" + android:minHeight="68dp" android:layout_marginBottom="20dp" android:maxLines="2" android:ellipsize="end" diff --git a/packages/SystemUI/res/layout/clipboard_overlay2.xml b/packages/SystemUI/res/layout/clipboard_overlay2.xml index 33ad2cd3a30f..521369e56652 100644 --- a/packages/SystemUI/res/layout/clipboard_overlay2.xml +++ b/packages/SystemUI/res/layout/clipboard_overlay2.xml @@ -31,7 +31,7 @@ android:layout_width="0dp" android:elevation="4dp" android:background="@drawable/shelf_action_chip_container_background" - android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal" + android:layout_marginStart="@dimen/overlay_action_container_minimum_edge_spacing" android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/actions_container" diff --git a/packages/SystemUI/res/layout/screenshot_shelf.xml b/packages/SystemUI/res/layout/screenshot_shelf.xml index 76f7f3b2c759..2cb4b0233a90 100644 --- a/packages/SystemUI/res/layout/screenshot_shelf.xml +++ b/packages/SystemUI/res/layout/screenshot_shelf.xml @@ -33,8 +33,7 @@ android:layout_width="wrap_content" android:elevation="4dp" android:background="@drawable/shelf_action_chip_container_background" - android:layout_marginHorizontal="@dimen/overlay_action_container_margin_horizontal" - android:layout_marginBottom="@dimen/screenshot_shelf_vertical_margin" + android:layout_marginHorizontal="@dimen/overlay_action_container_minimum_edge_spacing" app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toTopOf="@id/guideline" > @@ -61,7 +60,7 @@ android:id="@+id/screenshot_preview_border" android:layout_width="0dp" android:layout_height="0dp" - android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal" + android:layout_marginStart="@dimen/overlay_action_container_minimum_edge_spacing" android:layout_marginTop="@dimen/overlay_border_width_neg" android:layout_marginEnd="@dimen/overlay_border_width_neg" android:layout_marginBottom="@dimen/screenshot_shelf_vertical_margin" @@ -153,7 +152,7 @@ android:id="@+id/screenshot_message_container" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_marginHorizontal="@dimen/overlay_action_container_margin_horizontal" + android:layout_marginHorizontal="@dimen/overlay_action_container_minimum_edge_spacing" android:layout_marginTop="4dp" android:layout_marginBottom="@dimen/overlay_action_container_margin_bottom" android:paddingHorizontal="@dimen/overlay_action_container_padding_end" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index ac523c17df25..cc8f9c2ec305 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Langdruk om legstukke te pasmaak"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pasmaak legstukke"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App-ikoon vir gedeaktiveerde legstuk"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Wysig legstuk"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwyder"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Voeg legstuk by"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Pasmaak legstukke"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Legstukke op sluitskerm"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"kies legstuk"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"verwyder legstuk"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"plaas gekose legstuk"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Wissel gebruiker"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aftrekkieslys"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle programme en data in hierdie sessie sal uitgevee word."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Voer uitsetinstellings in"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volumeglyers is uitgevou"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volumeglyers is ingevou"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"demp %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ontdemp %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> speel tans op"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Oudio sal speel op"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Bel met"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 1236c976c57d..b00dc78d4de4 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ምግብሮችን ለማበጀት በረጅሙ ይጫኑ"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ምግብሮችን አብጅ"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"የመተግበሪያ አዶ ለተሰናከለ ምግብር"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ምግብርን አርትዕ"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"አስወግድ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ምግብር አክል"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ምግብሮችን አብጅ"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ምግብሮች በማያ ገጽ ቁልፍ ላይ"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ምግብር ይምረጡ"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ምግብር አስወግድ"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"በቦታ የተመረጠ ምግብር"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ተጠቃሚ ቀይር"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ወደታች ተጎታች ምናሌ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"በዚህ ክፍለ-ጊዜ ውስጥ ያሉ ሁሉም መተግበሪያዎች እና ውሂብ ይሰረዛሉ።"</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"የውጽዓት ቅንብሮችን ያስገቡ"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"የድምጽ ተንሸራታቾች ተዘርግቷል"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"የድምጽ ተንሸራታቾች ተሰብስቧል"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s ላይ ድምፀ-ከል አድርግ"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"የ%s ድምፀ-ከል አንሳ"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> እየተጫወተ ያለው በ"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"ኦዲዮ ይጫወታል በ"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"በጥሪ ላይ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 2eed2aa5b04e..d4981549654f 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -162,7 +162,7 @@ <string name="biometric_dialog_face_icon_description_confirmed" msgid="7918067993953940778">"تمّ التأكيد."</string> <string name="biometric_dialog_tap_confirm" msgid="9166350738859143358">"يمكنك النقر على \"تأكيد\" لإكمال المهمة."</string> <string name="biometric_dialog_tap_confirm_with_face" msgid="2378151312221818694">"تم فتح قفل جهازك عند تقريبه من وجهك."</string> - <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"تم فتح قفل جهازك عند تقريبه من وجهك. اضغط للمتابعة."</string> + <string name="biometric_dialog_tap_confirm_with_face_alt_1" msgid="439152621640507113">"تم فتح الجهاز بالتعرّف على وجهك. اضغط للمتابعة."</string> <string name="biometric_dialog_tap_confirm_with_face_alt_2" msgid="8586608186457385108">"تم التعرّف على الوجه. اضغط للمتابعة."</string> <string name="biometric_dialog_tap_confirm_with_face_alt_3" msgid="2192670471930606539">"تم التعرّف على الوجه. للمتابعة، اضغط على رمز فتح القفل."</string> <string name="biometric_dialog_authenticated" msgid="7337147327545272484">"مصادقة"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"اضغط مع الاستمرار لتخصيص التطبيقات المصغّرة."</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"تخصيص التطبيقات المصغَّرة"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"رمز التطبيق المصغّر غير المفعّل"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"تعديل التطبيق المصغَّر"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"إزالة"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"إضافة تطبيق مصغّر"</string> @@ -629,8 +631,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"الدخول إلى إعدادات إخراج الصوت"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"تم توسيع أشرطة تمرير الصوت"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"تم تصغير أشرطة تمرير الصوت"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"كتم صوت \"%s\""</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"إعادة صوت \"%s\""</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"تشغيل <xliff:g id="LABEL">%s</xliff:g> على"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"سيتم تشغيل الصوت على"</string> <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 16cd64b5d419..daefd834d85d 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ৱিজেট কাষ্টমাইজ কৰিবলৈ দীঘলীয়াকৈ টিপক"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ৱিজেট কাষ্টমাইজ কৰক"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"অক্ষম কৰা ৱিজেটৰ বাবে এপৰ চিহ্ন"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ৱিজেট সম্পাদনা কৰক"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"আঁতৰাওক"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ৱিজেট যোগ দিয়ক"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ৱিজেট কাষ্টমাইজ কৰক"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"লক স্ক্ৰীনত ৱিজেট"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ৱিজেট বাছনি কৰক"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ৱিজেট আঁতৰাওক"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"বাছনি কৰা ৱিজেটটো ৰাখক"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যৱহাৰকাৰী সলনি কৰক"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুল-ডাউনৰ মেনু"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই ছেশ্বনৰ আটাইবোৰ এপ্ আৰু ডেটা মচা হ\'ব।"</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"আউটপুট ছেটিং খোলক"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ভলিউমৰ শ্লাইডাৰ বিস্তাৰ কৰা আছে"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ভলিউমৰ শ্লাইডাৰ সংকোচন কৰা আছে"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s মিউট কৰক"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s আনমিউট কৰক"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"ইয়াত <xliff:g id="LABEL">%s</xliff:g> প্লে’ হৈ আছে"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"অডিঅ’ ইয়াত প্লে’ হ’ব"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"কল চলি আছে"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 69cec1c6d115..399e621f4fc7 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Basıb saxlayaraq vidcetləri fərdiləşdirin"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Vidcetləri fərdiləşdirin"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Deaktiv edilmiş vidcet üçün tətbiq ikonası"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Vidceti redaktə edin"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Silin"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidcet əlavə edin"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Vidcetləri fərdiləşdirin"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Kilid ekranındakı vidcetlər"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vidcet seçin"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"vidceti silin"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"seçilmiş vidceti yerləşdirin"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"aşağı çəkilən menyu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu sessiyada bütün tətbiqlər və data silinəcək."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Çıxış ayarlarını daxil edin"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Səs slayderləri genişləndirildi"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Səs slayderləri yığcamlaşdırıldı"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s seçimini səssiz edin"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s seçimini səssiz rejimdən çıxarın"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> tətbiqində oxudulur"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio oxudulacaq"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Zəng edilir"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index c2cc34afa758..1605666006c9 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugi pritisak za prilagođavanje vidžeta"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodi vidžete"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogućen vidžet"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Izmeni vidžet"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj vidžet"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Prilagodite vidžete"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Vidžeti na zaključanom ekranu"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"izaberite vidžet"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"uklonite vidžet"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"postavite izabrani vidžet"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zameni korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci u ovoj sesiji će biti izbrisani."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Unesite podešavanja izlaznog signala"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Klizači za jačinu zvuka su prošireni"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Klizači za jačinu zvuka su skupljeni"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"isključite zvuk za: %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"uključite zvuk za: %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> se pušta na"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk se pušta na"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Poziv na uređaju"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Tjuner za korisnički interfejs sistema"</string> <string name="status_bar" msgid="4357390266055077437">"Statusna traka"</string> <string name="demo_mode" msgid="263484519766901593">"Režim demonstracije za korisnički interfejs sistema"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index f956c0fc20a0..89a4701a3ba3 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -97,8 +97,7 @@ <string name="screenshot_left_boundary_pct" msgid="8502323556112287469">"Левая граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_right_boundary_pct" msgid="1201150713021779321">"Правая граніца: <xliff:g id="PERCENT">%1$d</xliff:g>%%"</string> <string name="screenshot_work_profile_notification" msgid="203041724052970693">"Захавана ў праграму \"<xliff:g id="APP">%1$s</xliff:g>\" (у працоўным профілі)"</string> - <!-- no translation found for screenshot_private_profile_notification (1704440899154243171) --> - <skip /> + <string name="screenshot_private_profile_notification" msgid="1704440899154243171">"Захавана ў праграму \"<xliff:g id="APP">%1$s</xliff:g>\" (у прыватным профілі)"</string> <string name="screenshot_default_files_app_name" msgid="8721579578575161912">"Файлы"</string> <string name="screenshot_detected_template" msgid="7940376642921719915">"Праграма \"<xliff:g id="APPNAME">%1$s</xliff:g>\" выявіла гэты здымак экрана."</string> <string name="screenshot_detected_multiple_template" msgid="7644827792093819241">"<xliff:g id="APPNAME">%1$s</xliff:g> і іншыя адкрытыя праграмы выявілі гэты здымак экрана."</string> @@ -448,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Доўга націскайце, каб наладзіць віджэты"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Наладзіць віджэты"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Значок праграмы для адключанага віджэта"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Змяніць віджэт"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Выдаліць"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Дадаць віджэт"</string> @@ -461,12 +462,9 @@ <string name="accessibility_action_label_close_communal_hub" msgid="6790396569621032333">"Закрыць віджэты на экране блакіроўкі"</string> <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Наладзіць віджэты"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Віджэты на экране блакіроўкі"</string> - <!-- no translation found for accessibility_action_label_select_widget (8897281501387398191) --> - <skip /> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"выбраць віджэт"</string> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"выдаліць віджэт"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"размясціць выбраны віджэт"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Перайсці да іншага карыстальніка"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"высоўнае меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усе праграмы і даныя гэтага сеанса будуць выдалены."</string> @@ -631,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Перайсці да налад вываду"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Меню з паўзункамі гучнасці разгорнута"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Меню з паўзункамі гучнасці згорнута"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"выключыць гук (%s)"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"уключыць гук (%s)"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> прайграецца тут:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Аўдыявыхад:"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ідзе выклік"</string> @@ -663,8 +667,7 @@ <string name="accessibility_status_bar_satellite_poor_connection" msgid="5231478574952724160">"Спадарожнікавая сувязь, дрэннае падключэнне"</string> <string name="accessibility_status_bar_satellite_good_connection" msgid="308079391708578704">"Спадарожнікавая сувязь, добрае падключэнне"</string> <string name="accessibility_status_bar_satellite_available" msgid="6514855015496916829">"Спадарожнікавая сувязь, падключэнне даступнае"</string> - <!-- no translation found for satellite_connected_carrier_text (118524195198532589) --> - <skip /> + <string name="satellite_connected_carrier_text" msgid="118524195198532589">"Экстраннае спадарожнікавае падключэнне"</string> <string name="accessibility_managed_profile" msgid="4703836746209377356">"Працоўны профіль"</string> <string name="tuner_warning_title" msgid="7721976098452135267">"Цікава для некаторых, але не для ўсіх"</string> <string name="tuner_warning" msgid="1861736288458481650">"Наладка сістэмнага інтэрфейсу карыстальніка дае вам дадатковыя спосабы наладжвання і дапасоўвання карыстальніцкага інтэрфейсу Android. Гэтыя эксперыментальныя функцыі могуць змяніцца, перастаць працаваць або знікнуць у будучых версіях. Карыстайцеся з асцярожнасцю."</string> @@ -869,8 +872,7 @@ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Дадаць плітку"</string> <string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Перамясціць на пазіцыю <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Дадаць на пазіцыю <xliff:g id="POSITION">%1$d</xliff:g>"</string> - <!-- no translation found for accessibilit_qs_edit_tile_add_move_invalid_position (2858467994472624487) --> - <skip /> + <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Няправільнае месца."</string> <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Пазіцыя <xliff:g id="POSITION">%1$d</xliff:g>"</string> <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Плітка дададзена"</string> <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Плітка выдалена"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index c9d0cd220b82..bdd9fd45e0b9 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Натиснете продължително за персонализ. на приспос."</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Персонализиране на приспособленията"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Икона на приложение за деактивирано приспособление"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Редактиране на приспособлението"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Премахване"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавяне на приспособление"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Персонализиране на приспособленията"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Приспособления на заключения екран"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"избиране на приспособление"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"премахване на приспособлението"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"поставяне на избраното приспособление"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Превключване между потребителите"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падащо меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Всички приложения и данни в тази сесия ще бъдат изтрити."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Отваряне на изходните настройки"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Плъзгачите за силата на звука са разгънати"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Плъзгачите за силата на звука са свити"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"спиране на звука на %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"включване на звука на %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Възпроизвеждане на <xliff:g id="LABEL">%s</xliff:g> на"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Аудиото ще се възпроизвежда на"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Активно обаждане"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index e2b4a6ddefe7..2c47b129b632 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"উইজেট কাস্টমাইজ করতে বেশিক্ষণ প্রেস করুন"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"উইজেট কাস্টমাইজ করুন"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"বন্ধ করা উইজেটের জন্য অ্যাপের আইকন"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"উইজেট এডিট করুন"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"সরান"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"উইজেট যোগ করুন"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"উইজেট কাস্টমাইজ করুন"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"লক স্ক্রিনে উইজেট"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"উইজেট বেছে নিন"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"উইজেট সরান"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"বেছে নেওয়া উইজেটটি রাখুন"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ব্যবহারকারী পাল্টে দিন"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"পুলডাউন মেনু"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"এই সেশনের সব অ্যাপ ও ডেটা মুছে ফেলা হবে।"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"আউটপুট সেটিংস লিখুন"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ভলিউম স্লাইডার বড় করা হয়েছে"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ভলিউম স্লাইডার আড়াল করা হয়েছে"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s মিউট করুন"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s আনমিউট করুন"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>-এ প্লে করা হচ্ছে"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"অডিও এতে প্লে করা হবে"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"কল চালু আছে"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"সিস্টেম UI টিউনার"</string> <string name="status_bar" msgid="4357390266055077437">"স্ট্যাটাস বার"</string> <string name="demo_mode" msgid="263484519766901593">"সিস্টেম UI ডেমো মোড"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 108bed8df6d1..8621b43bdafd 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -153,7 +153,7 @@ <string name="accessibility_send_smart_reply" msgid="8885032190442015141">"Pošalji"</string> <string name="cancel" msgid="1089011503403416730">"Otkaži"</string> <string name="biometric_dialog_logo" msgid="7681107853070774595">"Logotip aplikacije"</string> - <string name="biometric_dialog_confirm" msgid="2005978443007344895">"Potvrdite"</string> + <string name="biometric_dialog_confirm" msgid="2005978443007344895">"Potvrdi"</string> <string name="biometric_dialog_try_again" msgid="8575345628117768844">"Pokušaj ponovo"</string> <string name="biometric_dialog_empty_space_description" msgid="3330555462071453396">"Dodirnite da otkažete autentifikaciju"</string> <string name="biometric_dialog_face_icon_description_idle" msgid="4351777022315116816">"Pokušajte ponovo"</string> @@ -267,7 +267,7 @@ <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string> <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Nema dostupnih uparenih uređaja"</string> <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Dodirnite da povežete ili prekinete povezanost uređaja"</string> - <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Upari novi uređaj"</string> + <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Uparite novi uređaj"</string> <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Prikaži sve"</string> <string name="turn_on_bluetooth" msgid="5681370462180289071">"Koristi Bluetooth"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Povezano"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pritisnite i zadržite da prilagodite vidžete"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodite vidžete"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogućeni vidžet"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Uredite vidžet"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Uklanjanje"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajte vidžet"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Prilagođavanje vidžeta"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Vidžeti na zaključanom ekranu"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"odabir vidžeta"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"uklanjanje vidžeta"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"postavljanje odabranog vidžeta"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Zamijeni korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Sve aplikacije i podaci iz ove sesije će se izbrisati."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Unos postavki izlaza"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Klizači jačine zvuka su prošireni"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Klizači jačine zvuka su suženi"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"isključivanje parametra %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"uključivanje parametra %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Reproducira se <xliff:g id="LABEL">%s</xliff:g> na"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Reprodukcija zvuka na"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Poziv putem"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Podešavač za korisnički interfejs sistema"</string> <string name="status_bar" msgid="4357390266055077437">"Statusna traka"</string> <string name="demo_mode" msgid="263484519766901593">"Demo način rada Sistemskog UI-ja"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 48fadbc5e8c7..6ebfd86b85ba 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén premut per personalitzar els widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalitza els widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icona de l\'aplicació per a widget desactivat"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Edita el widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Suprimeix"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Afegeix un widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalitza els widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets a la pantalla de bloqueig"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"selecciona el widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"suprimeix el widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"col·loca el widget seleccionat"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Canvia d\'usuari"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Totes les aplicacions i les dades d\'aquesta sessió se suprimiran."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Introdueix opcions de configuració de sortida"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Els controls lliscants de volum s\'han desplegat"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Els controls lliscants de volum s\'han replegat"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"silencia %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"deixa de silenciar %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"S\'està reproduint <xliff:g id="LABEL">%s</xliff:g> a"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Es reproduirà a"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Trucant des de"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Personalitzador d\'interfície d\'usuari"</string> <string name="status_bar" msgid="4357390266055077437">"Barra d\'estat"</string> <string name="demo_mode" msgid="263484519766901593">"Mode de demostració de la IU del sistema"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index c90a0230aa31..7d2202da95c9 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -269,15 +269,15 @@ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Klepnutím zařízení připojíte nebo odpojíte"</string> <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Spárovat nové zařízení"</string> <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Zobrazit vše"</string> - <string name="turn_on_bluetooth" msgid="5681370462180289071">"Použít Bluetooth"</string> + <string name="turn_on_bluetooth" msgid="5681370462180289071">"Používat Bluetooth"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Připojeno"</string> <string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Sdílení zvuku"</string> <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Uloženo"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"odpojit"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktivovat"</string> <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Zítra znovu automaticky zapnout"</string> - <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Funkce jako Quick Share a Najdi moje zařízení využívají Bluetooth"</string> - <string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth se zapne zítra ráno"</string> + <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Bluetooth využívají funkce jako Quick Share a Najdi moje zařízení."</string> + <string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth se zapne zítra ráno."</string> <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Sdílení zvuku"</string> <string name="quick_settings_bluetooth_audio_sharing_button_sharing" msgid="8626191139359072540">"Sdílení zvuku"</string> <string name="quick_settings_bluetooth_secondary_label_battery_level" msgid="4182034939479344093">"Baterie: <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%s</xliff:g>"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dlouhým stisknutím můžete přizpůsobit widgety"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Přizpůsobit widgety"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikace s deaktivovaným widgetem"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Upravit widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstranit"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Přidat widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Přizpůsobit widgety"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgety na obrazovce uzamčení"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vybrat widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"odstranit widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"umístit vybraný widget"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Přepnout uživatele"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbalovací nabídka"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Veškeré aplikace a data v této relaci budou vymazána."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Otevřít nastavení výstupu"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Posuvníky hlasitosti jsou rozbalené"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Posuvníky hlasitosti jsou sbalené"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"ztlumíte %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"zapnete zvuk %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Přehrávání <xliff:g id="LABEL">%s</xliff:g> přes"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk se bude přehrávat přes"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Volání na zařízení"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Nástroj na ladění uživatelského rozhraní systému"</string> <string name="status_bar" msgid="4357390266055077437">"Stavový řádek"</string> <string name="demo_mode" msgid="263484519766901593">"Ukázkový režim uživatelského rozhraní systému"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 036f855b7a8f..ec03938ad7e2 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Hold fingeren nede for at tilpasse widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tilpas widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Appikon for deaktiveret widget"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Rediger widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tilføj widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Tilpas widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets på låseskærmen"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vælg widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"fjern widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"placer valgt widget"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skift bruger"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullemenu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apps og data i denne session slettes."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Angiv indstillinger for output"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Lydstyrkeskydere er udvidet"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Lydstyrkeskydere er skjult"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"slå lyden fra for %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"slå lyden til for %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Afspiller <xliff:g id="LABEL">%s</xliff:g> på"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Lyden afspilles på"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ringer på"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 42efdc22f1db..d38ad3ae6a83 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Lange drücken, um Widgets anzupassen"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widgets anpassen"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App-Symbol für deaktiviertes Widget"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Widget bearbeiten"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Entfernen"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget hinzufügen"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Widgets anpassen"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets auf dem Sperrbildschirm"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"Widget auswählen"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"Widget entfernen"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"ausgewähltes Widget in den Bearbeitungsmodus versetzen"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Nutzer wechseln"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Pull-down-Menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle Apps und Daten in dieser Sitzung werden gelöscht."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ausgabeeinstellungen angeben"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Lautstärkeregler maximiert"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Lautstärkeregler minimiert"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s stummzuschalten"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"Stummschaltung von %s aufzuheben"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Wiedergabe von <xliff:g id="LABEL">%s</xliff:g> über"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audiowiedergabe über"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Anruf auf"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Statusleiste"</string> <string name="demo_mode" msgid="263484519766901593">"Demomodus der System-UI"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 72ab8848c6ad..c6dad44b10e9 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Παρατεταμένο πάτημα για προσαρμογή γραφ. στοιχείων"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Προσαρμογή γραφικών στοιχείων"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Εικονίδιο εφαρμογής για απενεργοποιημένο γραφικό στοιχείο"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Επεξεργασία γραφικού στοιχείου"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Κατάργηση"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Προσθήκη γραφικού στοιχείου"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Προσαρμογή γραφικών στοιχείων"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Γραφικά στοιχεία στην οθόνη κλειδώματος"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"επιλογή γραφικού στοιχείου"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"κατάργηση γραφικού στοιχείου"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"τοποθέτηση επιλεγμένου γραφικού στοιχείου"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Εναλλαγή χρήστη"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"αναπτυσσόμενο μενού"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Όλες οι εφαρμογές και τα δεδομένα αυτής της περιόδου σύνδεσης θα διαγραφούν."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Εισαγωγή ρυθμίσεων εξόδου"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Τα ρυθμιστικά έντασης ήχου αναπτύχθηκαν"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Τα ρυθμιστικά έντασης ήχου συμπτύχθηκαν"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"σίγαση %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"κατάργηση σίγασης %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Αναπαραγωγή <xliff:g id="LABEL">%s</xliff:g> σε"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Ο ήχος θα παίξει σε"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ενεργή κλήση σε"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Γραμμή κατάστασης"</string> <string name="demo_mode" msgid="263484519766901593">"Λειτουργία επίδειξης διεπαφής χρήστη συστήματος"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index e414cd4e857a..cbb22984c351 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Customise widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets on lock screen"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"select widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"remove widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"place selected widget"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Enter output settings"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volume sliders expanded"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volume sliders collapsed"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"mute %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"unmute %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Playing <xliff:g id="LABEL">%s</xliff:g> on"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio will play on"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Calling on"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Status bar"</string> <string name="demo_mode" msgid="263484519766901593">"System UI demo mode"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 204f21d0c23a..fa007b67faee 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -447,6 +447,7 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customize widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customize widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string> + <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App icon for a widget being installed"</string> <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string> @@ -627,8 +628,10 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Enter output settings"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volume sliders expanded"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volume sliders collapsed"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"mute %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"unmute %s"</string> + <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Mute %s"</string> + <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Unmute %s"</string> + <string name="volume_panel_hint_muted" msgid="1124844870181285320">"muted"</string> + <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrate"</string> <string name="media_output_label_title" msgid="872824698593182505">"Playing <xliff:g id="LABEL">%s</xliff:g> on"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio will play on"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Calling on"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index e414cd4e857a..cbb22984c351 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Customise widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets on lock screen"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"select widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"remove widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"place selected widget"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Enter output settings"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volume sliders expanded"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volume sliders collapsed"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"mute %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"unmute %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Playing <xliff:g id="LABEL">%s</xliff:g> on"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio will play on"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Calling on"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Status bar"</string> <string name="demo_mode" msgid="263484519766901593">"System UI demo mode"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index e414cd4e857a..cbb22984c351 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customise widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customise widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Customise widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets on lock screen"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"select widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"remove widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"place selected widget"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Switch user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"All apps and data in this session will be deleted."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Enter output settings"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volume sliders expanded"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volume sliders collapsed"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"mute %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"unmute %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Playing <xliff:g id="LABEL">%s</xliff:g> on"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio will play on"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Calling on"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Status bar"</string> <string name="demo_mode" msgid="263484519766901593">"System UI demo mode"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index ee28a624b462..248360bac608 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -447,6 +447,7 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Long press to customize widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Customize widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App icon for disabled widget"</string> + <string name="icon_description_for_pending_widget" msgid="8413816401868001755">"App icon for a widget being installed"</string> <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remove"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Add widget"</string> @@ -627,8 +628,10 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Enter output settings"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volume sliders expanded"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volume sliders collapsed"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"mute %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"unmute %s"</string> + <string name="volume_panel_hint_mute" msgid="2153922288568199077">"Mute %s"</string> + <string name="volume_panel_hint_unmute" msgid="4831850937582282340">"Unmute %s"</string> + <string name="volume_panel_hint_muted" msgid="1124844870181285320">"muted"</string> + <string name="volume_panel_hint_vibrate" msgid="4136223145435914132">"vibrate"</string> <string name="media_output_label_title" msgid="872824698593182505">"Playing <xliff:g id="LABEL">%s</xliff:g> on"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio will play on"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Calling on"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 42424efdbeb6..28230f1d573d 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén presionado para personalizar los widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícono de la app de widget inhabilitado"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Modificar widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Agregar widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets en la pantalla de bloqueo"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"Seleccionar widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"quitar widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"colocar widget seleccionado"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú expandible"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán las aplicaciones y los datos de esta sesión."</string> @@ -619,7 +619,7 @@ <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Audio espacial"</string> <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Desactivar"</string> <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Fijar"</string> - <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Seg. de cabeza"</string> + <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Monitoreo de cabeza"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Presiona para cambiar el modo de timbre"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"silenciar"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"dejar de silenciar"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ingresar configuración de salida"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controles deslizantes del volumen expandidos"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controles deslizantes del volumen colapsados"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"silenciar %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"activar sonido %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Reproduciendo <xliff:g id="LABEL">%s</xliff:g> en"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Se reproducirá en"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Llamando en"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador de IU del sistema"</string> <string name="status_bar" msgid="4357390266055077437">"Barra de estado"</string> <string name="demo_mode" msgid="263484519766901593">"Modo demostración de la IU del sistema"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 77989e4ac7d3..fd2ac8582ae4 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantén pulsado para personalizar los widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icono de la aplicación de widget inhabilitado"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Añadir widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets en la pantalla de bloqueo"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"seleccionar widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"eliminar widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"colocar widget seleccionado"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar de usuario"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú desplegable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Se eliminarán todas las aplicaciones y datos de esta sesión."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Introducir los ajustes de salida"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controles deslizantes de volumen desplegados"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controles deslizantes de volumen contraídos"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"silenciar %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"dejar de silenciar %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Reproduciendo <xliff:g id="LABEL">%s</xliff:g> en"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Se reproducirá en"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Llamando desde"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Configurador de UI del sistema"</string> <string name="status_bar" msgid="4357390266055077437">"Barra de estado"</string> <string name="demo_mode" msgid="263484519766901593">"Modo Demo de UI del sistema"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index a3663a0bd958..7f97176012d7 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vajutage pikalt vidinate kohandamiseks"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Kohanda vidinaid"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Keelatud vidina rakenduseikoon"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Muuda vidinat"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Eemalda"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisa vidin"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Kohanda vidinaid"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Lukustuskuva vidinad"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vidina valimine"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"eemaldage vidin"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"asetage valitud vidin"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kasutaja vahetamine"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rippmenüü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Seansi kõik rakendused ja andmed kustutatakse."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Sisestage väljundseaded"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Helitugevuse liugurid laiendatud"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Helitugevuse liugurid ahendatud"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"vaigistab %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"tühistab %s vaigistuse"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Esitamine jätkub seadmes <xliff:g id="LABEL">%s</xliff:g>"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Heli esitatakse seadmes"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Helistamine seadmes"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Süsteemi kasutajaliidese tuuner"</string> <string name="status_bar" msgid="4357390266055077437">"Olekuriba"</string> <string name="demo_mode" msgid="263484519766901593">"Süsteemi kasutajaliidese demorežiim"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 23de72ea0527..685b5921bcd0 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widgetak pertsonalizatzeko, sakatu luze"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pertsonalizatu widgetak"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Desgaitutako widgetaren aplikazio-ikonoa"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Editatu widgeta"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Kendu"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Gehitu widget bat"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Pertsonalizatu widgetak"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Pantaila blokeatuko widgetak"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"hautatu widget bat"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"kendu widgeta"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"kokatu hautatutako widgeta"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Aldatu erabiltzailea"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"zabaldu menua"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Saioko aplikazio eta datu guztiak ezabatuko dira."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ireki emaitzaren ezarpenak"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Bolumenaren botoi lerrakorrak zabalduta daude"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Bolumenaren botoi lerrakorrak tolestuta daude"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"desaktibatu honen audioa: %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"aktibatu honen audioa: %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> hemen erreproduzitzen:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audioak abian jarraituko du hemen:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Honen bidez deitzen"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Sistemaren erabiltzaile-interfazearen konfiguratzailea"</string> <string name="status_bar" msgid="4357390266055077437">"Egoera-barra"</string> <string name="demo_mode" msgid="263484519766901593">"Sistemaren erabiltzaile-interfazearen demo modua"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 9feeaeeec31a..d21fdd330c11 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"برای سفارشیسازی ابزارکها، فشار طولانی دهید"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"سفارشیسازی ابزارکها"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"نماد برنامه برای ابزارک غیرفعال"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ویرایش ابزارک"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"برداشتن"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"افزودن ابزارک"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"سفارشیسازی ابزارکها"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ابزارکها در صفحه قفل"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"انتخاب ابزارک"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"برداشتن ابزارک"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"جایگذاری ابزارک انتخابشده"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"تغییر کاربر"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"منوی پایینپر"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"همه برنامهها و دادههای این جلسه حذف خواهد شد."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"تنظیمات خروجی را وارد کنید"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"لغزندههای صدا ازهم باز شدند"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"لغزندههای صدا جمع شدند"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"بیصدا کردن %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"باصدا کردن %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"درحال پخش <xliff:g id="LABEL">%s</xliff:g> در"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"صدا در این دستگاه پخش میشود:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"تماس برقرار است"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"تنظیمکننده واسط کاربری سیستم"</string> <string name="status_bar" msgid="4357390266055077437">"نوار وضعیت"</string> <string name="demo_mode" msgid="263484519766901593">"حالت نمایشی واسط کاربری سیستم"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 68319fd8b4b6..8910bf320593 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Yksilöi widgetit pitkällä painalluksella"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Muokkaa widgettejä"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Käytöstä poistetun widgetin sovelluskuvake"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Muokkaa widgetiä"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Poista"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lisää widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Muokkaa widgetejä"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgetit lukitusnäytöllä"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"valitse widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"poista widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"aseta valittu widget"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Vaihda käyttäjää"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"alasvetovalikko"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Kaikki sovellukset ja tämän istunnon tiedot poistetaan."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Lisää tuloasetukset"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Äänenvoimakkuuden liukusäätimet laajennettu"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Äänenvoimakkuuden liukusäätimet tiivistetty"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"mykistä: %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"poista mykistys: %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Toistetaan: <xliff:g id="LABEL">%s</xliff:g>"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audiota toistetaan laitteella"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Puhelu kesken:"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Tilapalkki"</string> <string name="demo_mode" msgid="263484519766901593">"Käyttöliittymän esittelytila"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index fd6ec7a371b8..df5f59f80dd1 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Maintenez le doigt pour personnaliser les widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personnaliser les widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icône d\'application pour un widget désactivé"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Modifier le widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Retirer"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personnaliser les widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets sur l\'écran de verrouillage"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"sélectionner le widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"retirer le widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"placer le widget sélectionné"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Entrer les paramètres de sortie"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Curseurs de volume développés"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Curseurs de volume réduits"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"Désactivez le son de %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"Réactivez le son de %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Lecture de <xliff:g id="LABEL">%s</xliff:g> sur"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Lecture audio sur"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Appel en cours"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Barre d\'état"</string> <string name="demo_mode" msgid="263484519766901593">"Mode Démo de l\'interface système"</string> @@ -1012,10 +1017,10 @@ <string name="accessibility_floating_button_hidden_notification_text" msgid="1457021647040915658">"Touchez pour afficher le bouton d\'accessibilité"</string> <string name="accessibility_floating_button_undo_message_label_text" msgid="9017658016426242640">"Le raccourci <xliff:g id="FEATURE_NAME">%s</xliff:g> a été retiré"</string> <string name="accessibility_floating_button_undo_message_number_text" msgid="4909270290725226075">"{count,plural, =1{# raccourci retiré}one{# raccourci retiré}many{# de raccourcis retirés}other{# raccourcis retirés}}"</string> - <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer dans coin sup. gauche"</string> - <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Déplacer dans coin sup. droit"</string> - <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Déplacer dans coin inf. gauche"</string> - <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Déplacer dans coin inf. droit"</string> + <string name="accessibility_floating_button_action_move_top_left" msgid="6253520703618545705">"Déplacer en haut à gauche"</string> + <string name="accessibility_floating_button_action_move_top_right" msgid="6106225581993479711">"Déplacer en haut à droite"</string> + <string name="accessibility_floating_button_action_move_bottom_left" msgid="8063394111137429725">"Déplacer en bas à gauche"</string> + <string name="accessibility_floating_button_action_move_bottom_right" msgid="6196904373227440500">"Déplacer en bas à droite"</string> <string name="accessibility_floating_button_action_move_to_edge_and_hide_to_half" msgid="662401168245782658">"Rapprocher du bord et masquer"</string> <string name="accessibility_floating_button_action_move_out_edge_and_show" msgid="8354760891651663326">"Éloigner du bord et afficher"</string> <string name="accessibility_floating_button_action_remove_menu" msgid="6730432848162552135">"Retirer"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 47f469ff4605..b02d547e08a8 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Appuyez de manière prolongée pour personnaliser les widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personnaliser les widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icône d\'appli du widget désactivé"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Modifier le widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Supprimer"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ajouter un widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personnaliser les widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets sur l\'écran de verrouillage"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"sélectionner un widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"supprimer le widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"positionner le widget sélectionné"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Changer d\'utilisateur"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu déroulant"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toutes les applications et les données de cette session seront supprimées."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Accéder aux paramètres de sortie"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Curseurs de volume développés"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Curseurs de volume réduits"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"couper le son de %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"réactiver le son de %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Diffusion de <xliff:g id="LABEL">%s</xliff:g> sur"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Lecture audio sur"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Appel défini sur"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index e7037b39fe33..8e2a0115b448 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pulsación longa para personalizar os widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icona da aplicación de widget desactivado"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Quitar"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engadir widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar os widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets na pantalla de bloqueo"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"seleccionar widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"quitar o widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"colocar o widget seleccionado"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Cambiar usuario"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menú despregable"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Eliminaranse todas as aplicacións e datos desta sesión."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Introducir a configuración de saída"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controis desprazables de volume despregados"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controis desprazables de volume contraídos"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"silenciar %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"activar o son de %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Reproducindo <xliff:g id="LABEL">%s</xliff:g> en"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Reproducirase en"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Chamada en curso"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Configurador da IU do sistema"</string> <string name="status_bar" msgid="4357390266055077437">"Barra de estado"</string> <string name="demo_mode" msgid="263484519766901593">"Modo de demostración da IU do sistema"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index b3c8e1eb5a88..c0f6be96115c 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"વિજેટ કસ્ટમાઇઝ કરવા માટે થોડીવાર દબાવી રાખો"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"વિજેટ કસ્ટમાઇઝ કરો"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"બંધ કરેલા વિજેટ માટેની ઍપનું આઇકન"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"વિજેટમાં ફેરફાર કરો"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"કાઢી નાખો"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"વિજેટ ઉમેરો"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"વિજેટ કસ્ટમાઇઝ કરો"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"લૉક સ્ક્રીન પર વિજેટ"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"વિજેટ પસંદ કરો"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"વિજેટ કાઢી નાખો"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"પસંદ કરેલું વિજેટ મૂકો"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"વપરાશકર્તા સ્વિચ કરો"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"પુલડાઉન મેનૂ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"આ સત્રમાંની તમામ ઍપ અને ડેટા કાઢી નાખવામાં આવશે."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"આઉટપુટના સેટિંગ દાખલ કરો"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"વૉલ્યૂમના સ્લાઇડર મોટા કરવામાં આવ્યા"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"વૉલ્યૂમના સ્લાઇડર નાના કરવામાં આવ્યા"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%sને મ્યૂટ કરો"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%sને અનમ્યૂટ કરો"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> વગાડી રહ્યાં છીએ"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"ઑડિયો આની પર વાગશે"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"કૉલ ચાલુ છે"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 28825845bb08..4cf74b5f0a08 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट पसंद के मुताबिक बनाने के लिए उसे दबाकर रखें"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेट अपनी पसंद के मुताबिक बनाएं"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"बंद किए गए विजेट के लिए ऐप्लिकेशन आइकॉन"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"विजेट में बदलाव करें"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"हटाएं"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोड़ें"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"विजेट अपनी पसंद के मुताबिक बनाएं"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"लॉक स्क्रीन पर विजेट"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"विजेट चुनें"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"विजेट हटाएं"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"चुने गए विजेट के लिए जगह चुनें"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"उपयोगकर्ता बदलें"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेन्यू"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"इस सेशन के सभी ऐप्लिकेशन और डेटा को हटा दिया जाएगा."</string> @@ -562,7 +562,7 @@ <string name="monitoring_description_parental_controls" msgid="8184693528917051626">"इस डिवाइस का प्रबंधन आपके अभिभावक करते हैं. अभिभावक आपके डिवाइस से जुड़ी जानकारी देख सकते हैं. साथ ही, इसे प्रबंधित कर सकते हैं. इनमें आपके इस्तेमाल किए गए ऐप्लिकेशन, जगह की जानकारी, और डिवाइस के इस्तेमाल में बिताए गए समय जैसी जानकारी शामिल है."</string> <string name="legacy_vpn_name" msgid="4174223520162559145">"वीपीएन"</string> <string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"TrustAgent की वजह से अनलॉक रखा गया है"</string> - <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"कई बार पुष्टि करने की कोशिश की वजह से, डिवाइस लॉक है"</string> + <string name="kg_prompt_after_adaptive_auth_lock" msgid="2587481497846342760">"कई बार पुष्टि करने की कोशिशों की वजह से, डिवाइस लॉक हो गया है"</string> <string name="keyguard_indication_after_adaptive_auth_lock" msgid="2323400645470712787">"डिवाइस लॉक हो गया है\nपुष्टि नहीं की जा सकी"</string> <string name="zen_mode_and_condition" msgid="5043165189511223718">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string> <string name="accessibility_volume_settings" msgid="1458961116951564784">"साउंड सेटिंग"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"आउटपुट की सेटिंग डालें"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"आवाज़ के स्लाइडर को बड़ा किया गया"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"आवाज़ के स्लाइडर को छोटा किया गया"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s को म्यूट करें"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s को अनम्यूट करें"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> इस पर चल रहा है"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"ऑडियो इस पर चलेगा"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"कॉल चालू है"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"सिस्टम यूज़र इंटरफ़ेस (यूआई) ट्यूनर"</string> <string name="status_bar" msgid="4357390266055077437">"स्टेटस बार"</string> <string name="demo_mode" msgid="263484519766901593">"सिस्टम यूज़र इंटरफ़ेस (यूआई) डेमो मोड"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index 560938bb882b..b211c9437539 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -369,8 +369,8 @@ <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"Srednji"</string> <string name="quick_settings_contrast_high" msgid="656049259587494499">"Visoki"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Slušna pomagala"</string> - <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušni uređaji"</string> - <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparivanje novog uređaja"</string> + <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Slušna pomagala"</string> + <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Uparite novi uređaj"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknite da biste uparili novi uređaj"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Ažuriranje unaprijed definiranih postavki nije uspjelo"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Želite li deblokirati mikrofon uređaja?"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Dugo pritisnite za prilagodbu widgeta"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagodi widgete"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogućeni widget"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Uredi widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Ukloni"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Prilagodi widgete"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgeti na zaključanom zaslonu"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"odaberi widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ukloni widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"postavi odabrani widget"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Promjena korisnika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"padajući izbornik"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Izbrisat će se sve aplikacije i podaci u ovoj sesiji."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Unesite postavke izlaza"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Proširivanje klizača za glasnoću"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Sažimanje klizača za glasnoću"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"isključili zvuk za sljedeće: %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"uključili zvuk za sljedeće: %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> se reproducira na"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk će se reproducirati na"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Pozivanje na uređaju"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Ugađanje korisničkog sučelja sustava"</string> <string name="status_bar" msgid="4357390266055077437">"Traka statusa"</string> <string name="demo_mode" msgid="263484519766901593">"Demo način korisničkog sučelja sustava"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 23166431bb28..e736537cc125 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nyomja meg hosszan a modulok személyre szabásához"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Modulok személyre szabása"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Letiltott modul alkalmazásikonja"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Modul szerkesztése"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Eltávolítás"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Modul hozzáadása"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Modulok személyre szabása"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Modulok a lezárási képernyőn"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"modul kiválasztása"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"modul törlése"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"kijelölt modul áthelyezése"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Felhasználóváltás"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"lehúzható menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"A munkamenetben található összes alkalmazás és adat törlődni fog."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Kimenet beállításainak megadása"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Hangerő-szabályozók kibontva"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Hangerő-szabályozók összecsukva"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s némítása"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s némításának feloldása"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> lejátszása itt:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Hang lejátszása itt:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Hívás folyamatban itt:"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Kezelőfelület-hangoló"</string> <string name="status_bar" msgid="4357390266055077437">"Állapotsor"</string> <string name="demo_mode" msgid="263484519766901593">"A rendszer kezelőfelületének demómódja"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 3d70b70556ab..6a905c598e00 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Երկար սեղմեք՝ վիջեթները հարմարեցնելու համար"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Հարմարեցնել վիջեթները"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Հավելվածի պատկերակ անջատված վիջեթի համար"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Փոփոխել վիջեթը"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Հեռացնել"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ավելացնել վիջեթ"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Հարմարեցնել վիջեթները"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Վիջեթներ կողպէկրանին"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ընտրել վիջեթ"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"հեռացնել վիջեթը"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"տեղադրել ընտրված վիջեթը"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Անջատել օգտվողին"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"իջնող ընտրացանկ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Այս աշխատաշրջանի բոլոր հավելվածներն ու տվյալները կջնջվեն:"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Բացել նվագարկման կարգավորումները"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Ձայնի ուժգնության սահիչները ծավալված են"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Ձայնի ուժգնության սահիչները ծալված են"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"անջատել ձայնը (%s)"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"միացնել ձայնը (%s)"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>. նվագարկվում է"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Աուդիոն կնվագարկի"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Զանգն ընթացքում է"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Համակարգի ՕՄ-ի կարգավորիչ"</string> <string name="status_bar" msgid="4357390266055077437">"Կարգավիճակի գոտի"</string> <string name="demo_mode" msgid="263484519766901593">"Համակարգի միջերեսի ցուցադրական ռեժիմ"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index bc7bb0fcd6a4..23d83974493c 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sesuaikan widget"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikon aplikasi untuk widget yang dinonaktifkan"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Hapus"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string> @@ -629,12 +631,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Masukkan setelan perangkat output"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Penggeser volume diluaskan"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Penggeser volume diciutkan"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"membisukan %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"membunyikan %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Memutar <xliff:g id="LABEL">%s</xliff:g> di"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio akan diputar di"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Menelepon di"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Penyetel Antarmuka Pengguna Sistem"</string> <string name="status_bar" msgid="4357390266055077437">"Bilah status"</string> <string name="demo_mode" msgid="263484519766901593">"Mode demo UI sistem"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index b30c89845138..2c77eb1f0345 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Haltu inni til að sérsníða græjur"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sérsníða græjur"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Forritstákn fyrir græju sem slökkt er á"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Breyta græju"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjarlægja"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Bæta græju við"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Sérsníða græjur"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Græjur á lásskjá"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"velja græju"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"fjarlægja græju"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"koma valinni græju fyrir"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Skipta um notanda"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"Fellivalmynd"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Öllum forritum og gögnum í þessari lotu verður eytt."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Færa inn stillingar úttaks"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Stækkaðir hljóðstyrkssleðar"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Minnkaðir hljóðstyrkssleðar"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"þagga %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"kveikja á hljóði %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Í spilun í <xliff:g id="LABEL">%s</xliff:g>"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Hljóð heldur áfram að spilast"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Símtal í gangi"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Fínstillingar kerfisviðmóts"</string> <string name="status_bar" msgid="4357390266055077437">"Stöðustika"</string> <string name="demo_mode" msgid="263484519766901593">"Prufustilling kerfisviðmóts"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 210209958ae9..056c2867388a 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Premi a lungo per personalizzare i widget"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizza widget"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icona dell\'app per widget disattivati"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Modifica widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Rimuovi"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Aggiungi widget"</string> @@ -629,12 +631,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Inserisci impostazioni di uscita"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Cursori volume espansi"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Cursori volume compressi"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"disattivare audio di %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"riattivare audio di %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> in riproduzione su"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio riprodotto su:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Chiamata in corso"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Ottimizzatore UI di sistema"</string> <string name="status_bar" msgid="4357390266055077437">"Barra di stato"</string> <string name="demo_mode" msgid="263484519766901593">"Modalità demo dell\'interfaccia utente di sistema"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 5be4172db9d1..6670b097ac53 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -269,7 +269,7 @@ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"אפשר להקיש כדי להתחבר למכשיר או להתנתק ממנו"</string> <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"התאמה של מכשיר חדש"</string> <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"הצגת הכול"</string> - <string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth"</string> + <string name="turn_on_bluetooth" msgid="5681370462180289071">"שימוש ב-Bluetooth"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"מחובר"</string> <string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"שיתוף אודיו"</string> <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"נשמר"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"לוחצים לחיצה ארוכה כדי להתאים אישית את הווידג\'טים"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"התאמה אישית של ווידג\'טים"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"סמל האפליקציה לווידג\'ט שהושבת"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"עריכת הווידג\'ט"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"הסרה"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"הוספת ווידג\'ט"</string> @@ -629,12 +631,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"הזנה של הגדרות הפלט"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"פסי ההזזה של עוצמת הקול במצב מורחב"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"פסי ההזזה של עוצמת הקול במצב מכווץ"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"השתקה של %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ביטול ההשתקה של %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"הפעלה של <xliff:g id="LABEL">%s</xliff:g> במכשיר"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"האודיו יופעל במכשיר"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"מתבצעת שיחה במכשיר"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"שורת סטטוס"</string> <string name="demo_mode" msgid="263484519766901593">"מצב הדגמה בממשק המשתמש של המערכת"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 62a3a4324658..e3c0dbcf9992 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -272,7 +272,7 @@ <string name="turn_on_bluetooth" msgid="5681370462180289071">"Bluetooth を使用"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"接続しました"</string> <string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"音声の共有"</string> - <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"保存しました"</string> + <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"保存済み"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"接続を解除"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"有効化"</string> <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"明日自動的に ON に戻す"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長押ししてウィジェットをカスタマイズ"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ウィジェットのカスタマイズ"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"無効なウィジェットのアプリアイコン"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ウィジェットを編集"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"削除"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ウィジェットを追加"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ウィジェットのカスタマイズ"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ロック画面のウィジェット"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ウィジェットを選択"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ウィジェットを削除"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"選択したウィジェットを配置"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ユーザーを切り替える"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"プルダウン メニュー"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"このセッションでのアプリとデータはすべて削除されます。"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"出力の設定を入力してください"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"音量スライダーを開きました"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"音量スライダーを閉じました"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s をミュート"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s のミュートを解除"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> の再生先:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"音声の再生先"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"通話中"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"システムUI調整ツール"</string> <string name="status_bar" msgid="4357390266055077437">"ステータスバー"</string> <string name="demo_mode" msgid="263484519766901593">"システム UI デモモード"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 2a4f5d68c1f7..0251ac0e9d7c 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ხანგრძლივად დააჭირეთ ვიჯეტების მოსარგებად"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ვიჯეტების მორგება"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"აპის ხატულა გათიშული ვიჯეტისთვის"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ვიჯეტის რედაქტირება"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"ამოშლა"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ვიჯეტის დამატება"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ვიჯეტების მორგება"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ვიჯეტები ჩაკეტილ ეკრანზე"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ვიჯეტის არჩევა"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ვიჯეტის ამოშლა"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"არჩეული ვიჯეტის განთავსება"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"მომხმარებლის გადართვა"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ჩამოშლადი მენიუ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ამ სესიის ყველა აპი და მონაცემი წაიშლება."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"აუდიოს გამოსვლის პარამეტრების გახსნა"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ხმის სლაიდერების გაფართოება"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ხმის სლაიდერების ჩაკეცვა"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s-ის დადუმება"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s-ის დადუმების მოხსნა"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"უკრავს <xliff:g id="LABEL">%s</xliff:g>:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"აუდიო დაიკვრება"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"მიმდინარეობს ზარი"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 398677ee6396..9c96a4eb6b60 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерді бейімдеу үшін ұзақ басып тұрыңыз."</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджеттерді реттеу"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Өшірілген виджеттің қолданба белгішесі"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Виджетті өзгерту"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Өшіру"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет қосу"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Виджеттерді бейімдеу"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Құлыптаулы экрандағы виджеттер"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"виджет таңдау"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"виджетті өшіру"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"таңдалған виджетті орналастыру"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Пайдаланушыны ауыстыру"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ашылмалы мәзір"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Осы сеанстағы барлық қолданба мен дерек жойылады."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Шығыс параметрлерін енгізу"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Дыбыс деңгейінің жүгірткі реттегіштері жайылды."</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Дыбыс деңгейінің жүгірткі реттегіштері жиылды."</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s дыбысын өшіру"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s дыбысын қосу"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ойнатылатын құрылғы:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Аудио ойнатылатын құрылғы:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Қоңырау шалып жатыр"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Жүйелік пайдаланушылық интерфейс тюнері"</string> <string name="status_bar" msgid="4357390266055077437">"Күйін көрсету жолағы"</string> <string name="demo_mode" msgid="263484519766901593">"Жүйе интерфейсінің демо режимі"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index e32da00ef6a9..dc9a747a70b4 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ចុចឱ្យយូរ ដើម្បីប្ដូរធាតុក្រាហ្វិកតាមបំណង"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ប្ដូរធាតុក្រាហ្វិកតាមបំណង"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"រូបកម្មវិធីសម្រាប់ធាតុក្រាហ្វិកដែលបានបិទ"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"កែធាតុក្រាហ្វិក"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"ដកចេញ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"បញ្ចូលធាតុក្រាហ្វិក"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ប្ដូរធាតុក្រាហ្វិកតាមបំណង"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ធាតុក្រាហ្វិកនៅលើអេក្រង់ចាក់សោ"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ជ្រើសរើសធាតុក្រាហ្វិក"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ដកធាតុក្រាហ្វិកចេញ"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"ដាក់ធាតុក្រាហ្វិកដែលបានជ្រើសរើស"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ប្ដូរអ្នកប្រើ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ម៉ឺនុយទាញចុះ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"កម្មវិធី និងទិន្នន័យទាំងអស់ក្នុងវគ្គនេះនឹងត្រូវលុប។"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ចូលការកំណត់ឧបករណ៍មេឌៀ"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"បានពង្រីកគ្រាប់រំកិលកម្រិតសំឡេង"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"បានបង្រួមគ្រាប់រំកិលកម្រិតសំឡេង"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"បិទសំឡេង %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"បើកសំឡេង %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"កំពុងចាក់ <xliff:g id="LABEL">%s</xliff:g> នៅលើ"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"សំឡេងនឹងលេងនៅលើ"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"កំពុងនិយាយទូរសព្ទ"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"កម្មវិធីសម្រួល UI ប្រព័ន្ធ"</string> <string name="status_bar" msgid="4357390266055077437">"របារស្ថានភាព"</string> <string name="demo_mode" msgid="263484519766901593">"មុខងារសាកល្បង UI ប្រព័ន្ធ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index e217f8e20470..46a679cff801 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -368,7 +368,7 @@ <string name="quick_settings_contrast_standard" msgid="2538227821968061832">"ಪ್ರಮಾಣಿತ"</string> <string name="quick_settings_contrast_medium" msgid="5158352575583902566">"ಮಧ್ಯಮ"</string> <string name="quick_settings_contrast_high" msgid="656049259587494499">"ಹೆಚ್ಚು"</string> - <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ಹಿಯರಿಂಗ್ ಸಾಧನಗಳು"</string> + <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ಶ್ರವಣ ಸಾಧನಗಳು"</string> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ಹಿಯರಿಂಗ್ ಸಾಧನಗಳು"</string> <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ಹೊಸ ಸಾಧನವನ್ನು ಪೇರ್ ಮಾಡಿ"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ಹೊಸ ಸಾಧನವನ್ನು ಜೋಡಿಸಲು ಕ್ಲಿಕ್ ಮಾಡಿ"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ವಿಜೆಟ್ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಲು ದೀರ್ಘಕಾಲ ಒತ್ತಿರಿ"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ವಿಜೆಟ್ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾದ ವಿಜೆಟ್ಗಾಗಿ ಆ್ಯಪ್ ಐಕಾನ್"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ವಿಜೆಟ್ ಅನ್ನು ಎಡಿಟ್ ಮಾಡಿ"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"ತೆಗೆದುಹಾಕಿ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ವಿಜೆಟ್ ಅನ್ನು ಸೇರಿಸಿ"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ವಿಜೆಟ್ಗಳನ್ನು ಕಸ್ಟಮೈಸ್ ಮಾಡಿ"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ಲಾಕ್ ಸ್ಕ್ರೀನ್ನಲ್ಲಿ ವಿಜೆಟ್ಗಳು"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ವಿಜೆಟ್ ಅನ್ನು ಆಯ್ಕೆ ಮಾಡಿ"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ವಿಜೆಟ್ ಅನ್ನು ತೆಗೆದುಹಾಕಿ"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"ಆಯ್ಕೆಮಾಡಿದ ವಿಜೆಟ್ ಅನ್ನು ಇರಿಸಿ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ಪುಲ್ಡೌನ್ ಮೆನು"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ಈ ಸೆಶನ್ನಲ್ಲಿನ ಎಲ್ಲಾ ಆ್ಯಪ್ಗಳು ಮತ್ತು ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ."</string> @@ -594,9 +594,9 @@ <string name="screen_pinning_negative" msgid="6882816864569211666">"ಬೇಡ"</string> <string name="screen_pinning_start" msgid="7483998671383371313">"ಆ್ಯಪ್ ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string> <string name="screen_pinning_exit" msgid="4553787518387346893">"ಆ್ಯಪ್ ಅನ್ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string> - <string name="stream_voice_call" msgid="7468348170702375660">"ಕರೆಮಾಡಿ"</string> + <string name="stream_voice_call" msgid="7468348170702375660">"ಕರೆ ಮಾಡಿ"</string> <string name="stream_system" msgid="7663148785370565134">"ಸಿಸ್ಟಂ"</string> - <string name="stream_ring" msgid="7550670036738697526">"ರಿಂಗ್"</string> + <string name="stream_ring" msgid="7550670036738697526">"ರಿಂಗ್ ಮಾಡಿ"</string> <string name="stream_music" msgid="2188224742361847580">"ಮಾಧ್ಯಮ"</string> <string name="stream_alarm" msgid="16058075093011694">"ಅಲಾರಮ್"</string> <string name="stream_notification" msgid="7930294049046243939">"ನೋಟಿಫಿಕೇಶನ್"</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ಔಟ್ಪುಟ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ವಾಲ್ಯೂಮ್ ಸ್ಲೈಡರ್ಗಳನ್ನು ವಿಸ್ತೃತಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ವಾಲ್ಯೂಮ್ ಸ್ಲೈಡರ್ಗಳನ್ನು ಕುಗ್ಗಿಸಲಾಗಿದೆ"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s ಮ್ಯೂಟ್ ಮಾಡಿ"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s ಅನ್ಮ್ಯೂಟ್ ಮಾಡಿ"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ನಲ್ಲಿ ಪ್ಲೇ ಆಗು..."</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"ಇದರಲ್ಲಿ ಪ್ಲೇ ಆಗುತ್ತದೆ"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"ಕರೆ ಮಾಡಲಾಗುತ್ತಿದೆ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 3ef3dc862bfb..54dcfce6d5b8 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"위젯을 맞춤설정하려면 길게 누르기"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"위젯 맞춤설정"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"사용 중지된 위젯의 앱 아이콘"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"위젯 수정"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"삭제"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"위젯 추가"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"위젯 맞춤설정"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"잠금 화면의 위젯"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"위젯 선택"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"위젯 삭제"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"선택한 위젯 배치"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"사용자 전환"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"풀다운 메뉴"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"이 세션에 있는 모든 앱과 데이터가 삭제됩니다."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"출력 설정 열기"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"볼륨 슬라이더 펼침"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"볼륨 슬라이더 접힘"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s 음소거"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s 음소거 해제"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> 재생 위치:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"오디오 재생 위치:"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"전화 거는 중"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index a75d0d5fe2e7..a224ac78d599 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджеттерди ыңгайлаштыруу үчүн кое бербей басып туруңуз"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджеттерди ыңгайлаштыруу"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Өчүрүлгөн виджет үчүн колдонмонун сүрөтчөсү"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Виджетти түзөтүү"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Өчүрүү"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет кошуу"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Виджеттерди ыңгайлаштыруу"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Кулпуланган экрандагы виджеттер"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"виджет тандоо"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"виджетти алып салуу"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"тандалган виджетти жайгаштыруу"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Колдонуучуну которуу"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ылдый түшүүчү меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Бул сеанстагы бардык колдонмолор жана аларга байланыштуу нерселер өчүрүлөт."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Чыгаруу параметрлерин киргизүү"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Үндүн катуулугунун сыдырмалары жайып көрсөтүлдү"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Үндүн катуулугунун сыдырмалары жыйыштырылды"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s үнүн басуу"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s үнүн чыгаруу"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> аркылуу ойнотулууда"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Аудио кайсы жерде ойнотулат:"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Чалууда"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index eca041e8acf1..88866e37d07a 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ກົດຄ້າງໄວ້ເພື່ອປັບແຕ່ງວິດເຈັດ"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ປັບແຕ່ງວິດເຈັດ"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ໄອຄອນແອັບສຳລັບວິດເຈັດທີ່ຖືກປິດການນຳໃຊ້"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ແກ້ໄຂວິດເຈັດ"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"ລຶບອອກ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ເພີ່ມວິດເຈັດ"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ປັບແຕ່ງວິດເຈັດ"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ວິດເຈັດຢູ່ໜ້າຈໍລັອກ"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ເລືອກວິດເຈັດ"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ລຶບວິດເຈັດອອກ"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"ວາງວິດເຈັດທີ່ເລືອກ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ສະຫຼັບຜູ້ໃຊ້"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ເມນູແບບດຶງລົງ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ແອັບຯແລະຂໍ້ມູນທັງໝົດໃນເຊດຊັນນີ້ຈະຖືກລຶບອອກ."</string> @@ -629,10 +629,16 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ໃສ່ການຄັ້ງຄ່າເອົ້າພຸດ"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ຂະຫຍາຍສະໄລເດີລະດັບສຽງແລ້ວ"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ຫຍໍ້ສະໄລເດີລະດັບສຽງລົງແລ້ວ"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"ປິດສຽງ %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ເຊົາປິດສຽງ %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"ກຳລັງຫຼິ້ນ <xliff:g id="LABEL">%s</xliff:g> ໃນ"</string> - <string name="media_output_title_without_playing" msgid="3825663683169305013">"ສຽງຈະຫຼິ້ນຕໍ່ໄປ"</string> + <string name="media_output_title_without_playing" msgid="3825663683169305013">"ສຽງຈະຫຼິ້ນຢູ່"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"ກຳລັງໂທ"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"ແຖບສະຖານະ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index fa5790ce8e26..46ac3044f765 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Ilgai paspauskite, kad tinkintumėte valdiklius"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tinkinti valdiklius"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Išjungto valdiklio programos piktograma"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Redaguoti valdiklį"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Pašalinti"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridėti valdiklį"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Tinkinti valdiklius"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Valdikliai užrakinimo ekrane"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"pasirinkite valdiklį"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"pašalinti valdiklį"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"padėti pasirinktą valdiklį"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Perjungti naudotoją"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"išplečiamasis meniu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bus ištrintos visos šios sesijos programos ir duomenys."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Įveskite išvesties nustatymus"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Garsumo šliaužikliai išskleisti"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Garsumo šliaužikliai sutraukti"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"nutildyti %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"įjungti garsą %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Leidžiama „<xliff:g id="LABEL">%s</xliff:g>“"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Garsas bus leidžiamas"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Skambinama"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 9e01526dcb52..979f59e3374f 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -370,7 +370,7 @@ <string name="quick_settings_contrast_high" msgid="656049259587494499">"Augsts"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Dzirdes aparāti"</string> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Dzirdes aparāti"</string> - <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Savienojiet pārī jaunu ierīci"</string> + <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Savienot pārī jaunu ierīci"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Noklikšķiniet, lai savienotu pārī jaunu ierīci"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Nevarēja atjaunināt pirmsiestatījumu"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Vai atbloķēt ierīces mikrofonu?"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nospiediet un turiet, lai pielāgotu logrīkus."</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Pielāgot logrīkus"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Lietotnes ikona atspējotam logrīkam"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Rediģēt logrīku"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Noņemt"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pievienot logrīku"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Pielāgot logrīkus"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Logrīki bloķēšanas ekrānā"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"atlasīt logrīku"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"noņemt logrīku"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"novietot atlasīto logrīku"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mainīt lietotāju"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"novelkamā izvēlne"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tiks dzēstas visas šīs sesijas lietotnes un dati."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Atvērt izvades iestatījumus"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Skaļuma slīdņi izvērsti"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Skaļuma slīdņi sakļauti"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"izslēgt skaņu straumei %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ieslēgt skaņu straumei %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> — atskaņošana šeit:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio tiks atskaņots šeit:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Aktīvs zvans ierīcē"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Sistēmas saskarnes regulators"</string> <string name="status_bar" msgid="4357390266055077437">"Statusa josla"</string> <string name="demo_mode" msgid="263484519766901593">"Sistēmas lietotāja saskarnes demonstrācijas režīms"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index d1e26e5d8565..e305c9e5fee1 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Притиснете долго за да ги приспособите виџетите"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Приспособете ги виџетите"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Икона за апликација за оневозможен виџет"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Изменување виџети"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Отстранува"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додајте виџет"</string> @@ -596,14 +598,14 @@ <string name="screen_pinning_exit" msgid="4553787518387346893">"Апликацијата е откачена"</string> <string name="stream_voice_call" msgid="7468348170702375660">"Повик"</string> <string name="stream_system" msgid="7663148785370565134">"Систем"</string> - <string name="stream_ring" msgid="7550670036738697526">"Ѕвони"</string> + <string name="stream_ring" msgid="7550670036738697526">"Ѕвонење"</string> <string name="stream_music" msgid="2188224742361847580">"Аудиовизуелни содржини"</string> <string name="stream_alarm" msgid="16058075093011694">"Аларм"</string> <string name="stream_notification" msgid="7930294049046243939">"Известување"</string> <string name="stream_bluetooth_sco" msgid="6234562365528664331">"Bluetooth"</string> <string name="stream_dtmf" msgid="7322536356554673067">"Двојна повеќетонска фреквенција"</string> <string name="stream_accessibility" msgid="3873610336741987152">"Пристапност"</string> - <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ѕвони"</string> + <string name="volume_ringer_status_normal" msgid="1339039682222461143">"Ѕвонење"</string> <string name="volume_ringer_status_vibrate" msgid="6970078708957857825">"Вибрации"</string> <string name="volume_ringer_status_silent" msgid="3691324657849880883">"Исклучи звук"</string> <string name="media_device_cast" msgid="4786241789687569892">"Емитување"</string> @@ -629,12 +631,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Внесете ги поставките за излез"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Лизгачите за јачина на звукот се проширени"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Лизгачите за јачина на звукот се собрани"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"исклучување звук на %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"вклучување звук на %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>: пуштено на"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Аудиото ќе се пушти на"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Повик во тек"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Адаптер на УИ на системот"</string> <string name="status_bar" msgid="4357390266055077437">"Статусна лента"</string> <string name="demo_mode" msgid="263484519766901593">"Демо-режим на кориснички интерфејс на систем"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 79be0f17fb5a..c14cc418d5a8 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കാൻ ദീർഘനേരം അമർത്തുക"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കുക"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"പ്രവർത്തനരഹിതമാക്കിയ വിജറ്റിനുള്ള ആപ്പ് ഐക്കൺ"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"വിജറ്റ് എഡിറ്റ് ചെയ്യുക"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"നീക്കം ചെയ്യുക"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"വിജറ്റ് ചേർക്കുക"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"വിജറ്റുകൾ ഇഷ്ടാനുസൃതമാക്കുക"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ലോക്ക് സ്ക്രീനിൽ വിജറ്റുകൾ"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"വിജറ്റ് തിരഞ്ഞെടുക്കുക"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"വിജറ്റ് നീക്കം ചെയ്യുക"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"തിരഞ്ഞെടുത്ത വിജറ്റ് നൽകുക"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ഉപയോക്താവ് മാറുക"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"പുൾഡൗൺ മെനു"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ഈ സെഷനിലെ എല്ലാ ആപ്പുകളും ഡാറ്റയും ഇല്ലാതാക്കും."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ഔട്ട്പുട്ട് ക്രമീകരണം നൽകുക"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"വോളിയം സ്ലൈഡറുകൾ വികസിപ്പിച്ചു"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"വോളിയം സ്ലൈഡറുകൾ ചുരുക്കി"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s മ്യൂട്ട് ചെയ്യുക"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s അൺമ്യൂട്ട് ചെയ്യുക"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> എന്നതിൽ പ്ലേ ചെയ്യുന്നു"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"ഓഡിയോ പ്ലേ ചെയ്യും"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"കോൾ പുരോഗമിക്കുന്നു"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 93304d64e511..573c8ff7e7d6 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Виджетүүдийг өөрчлөхийн тулд удаан дарна уу"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Виджетүүдийг өөрчлөх"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Идэвхгүй болгосон виджетийн аппын дүрс тэмдэг"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Виджетийг засах"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Хасах"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Виджет нэмэх"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Виджетийг өөрчлөх"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Түгжээтэй дэлгэц дээрх виджетүүд"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"виджет сонгох"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"виджетийг хасах"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"сонгосон виджетийг байрлуулах"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Хэрэглэгчийг сэлгэх"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"эвхмэл цэс"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Энэ харилцан үйлдлийн бүх апп болон дата устах болно."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Оролтын тохиргоог оруулах"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Дууны түвшний гулсуулагчдыг дэлгэсэн"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Дууны түвшний гулсуулагчдыг хураасан"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s-н дууг хаах"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s-н дууг нээх"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> тоглуулж байна"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Аудиог дараахад тоглуулна"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Дуудлага хийгдэж буй:"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Системийн UI Тохируулагч"</string> <string name="status_bar" msgid="4357390266055077437">"Статус самбар"</string> <string name="demo_mode" msgid="263484519766901593">"Системийн UI демо горим"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 0aad76430e82..3667f1e9dcd1 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेट कस्टमाइझ करण्यासाठी प्रेस करून ठेवा"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेट कस्टमाइझ करा"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"बंद केलेल्या विजेटच्या अॅपचे आयकन"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"विजेट संपादित करा"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"काढून टाका"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट जोडा"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"विजेट कस्टमाइझ करा"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"लॉक स्क्रीनवरील विजेट"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"विजेट निवडा"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"विजेट काढून टाका"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"निवडलेले विजेट ठेवा"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"वापरकर्ता स्विच करा"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनू"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"या सत्रातील सर्व अॅप्स आणि डेटा हटवला जाईल."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"आउटपुट सेटिंग्ज एंटर करा"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"व्हॉल्यूम स्लायडर विस्तारित केले आहेत"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"व्हॉल्यूम स्लायडर कोलॅप्स केले आहेत"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s म्यूट करा"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s अनम्यूट करा"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> वर प्ले करत आहे"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"यावर ऑडिओ प्ले होईल"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"यावर कॉल करत आहे"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 60c028d40869..60aedfa449cf 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -275,7 +275,7 @@ <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Disimpan"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"putuskan sambungan"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"aktifkan"</string> - <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Dihidupkan sekali lagi esok secara automatik"</string> + <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"Dihidupkan lagi esok secara automatik"</string> <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"Ciri seperti Quick Share dan Find My Device menggunakan Bluetooth"</string> <string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"Bluetooth akan dihidupkan esok pagi"</string> <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"Perkongsian Audio"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tekan lama untuk menyesuaikan widget"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Sesuaikan widget"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikon apl untuk melumpuhkan widget"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Edit widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Alih keluar"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Tambahkan widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Sesuaikan widget"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widget pada skrin kunci"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"pilih widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"alih keluar widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"letakkan widget dipilih"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Tukar pengguna"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu tarik turun"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Semua apl dan data dalam sesi ini akan dipadam."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Masukkan tetapan output"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Peluncur kelantangan dikembangkan"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Peluncur kelantangan dikuncupkan"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"redamkan %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"nyahredamkan %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Memainkan <xliff:g id="LABEL">%s</xliff:g> pada"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio dimainkan pada"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Membuat panggilan"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index dcbf837df5ec..b7398d0efa13 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ဝိဂျက်များ စိတ်ကြိုက်လုပ်ရန် ကြာကြာနှိပ်ထားပါ"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ဝိဂျက်များကို စိတ်ကြိုက်လုပ်ရန်"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ပိတ်ထားသော ဝိဂျက်အတွက် အက်ပ်သင်္ကေတ"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ဝိဂျက်ပြင်ရန်"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"ဖယ်ရှားရန်"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ဝိဂျက်ထည့်ရန်"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ဝိဂျက်များကို စိတ်ကြိုက်လုပ်ရန်"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"လော့ခ်မျက်နှာပြင်ရှိ ဝိဂျက်များ"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ဝိဂျက် ရွေးရန်"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ဝိဂျက် ဖယ်ရှားရန်"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"ရွေးချယ်ထားသော ဝိဂျက်ကို တင်ရန်"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ဆွဲချမီနူး"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ဒီချိတ်ဆက်မှု ထဲက အက်ပ်များ အားလုံး နှင့် ဒေတာကို ဖျက်ပစ်မည်။"</string> @@ -619,7 +619,7 @@ <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"ထောင့်စုံအော်ဒီယို"</string> <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"ပိတ်"</string> <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"ပုံသေ"</string> - <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ခေါင်းလှုပ်ရှားမှု စောင့်ကြည့်ခြင်း"</string> + <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"ခေါင်းလှုပ်ရှားမှု"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"ဖုန်းခေါ်သံမုဒ်သို့ ပြောင်းရန် တို့ပါ"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"အသံပိတ်ရန်"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"အသံဖွင့်ရန်"</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"အထွက် ဆက်တင်များ ထည့်ရန်"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"အသံအတိုးအကျယ် ရွှေ့တုံးများ ပိုပြထားသည်"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"အသံအတိုးအကျယ် ရွှေ့တုံးများ လျှော့ပြထားသည်"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s အသံပိတ်ရန်"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s အသံပြန်ဖွင့်ရန်"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ဖွင့်မည့်နေရာ"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"အသံဖွင့်မည့်နေရာ"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"ဖုန်းဆက်နေသည်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 2724a5174752..2b131c7e5407 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Trykk lenge for å tilpasse modulene"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tilpass moduler"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Appikon for deaktivert modul"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Endre modul"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Fjern"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Legg til modul"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Tilpass moduler"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Moduler på låseskjermen"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"velg modul"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"fjern modul"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"plasser den valgte modulen"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Bytt bruker"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullegardinmeny"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alle apper og data i denne økten blir slettet."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Angi utdatainnstillinger"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Glidebrytere for volum er skjult"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Glidebrytere for volum er skjult"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"kutt lyden til %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"slå på lyden til %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Spiller av <xliff:g id="LABEL">%s</xliff:g> på"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Lyden spilles av på"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Aktiv samtale på"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Statusrad"</string> <string name="demo_mode" msgid="263484519766901593">"Demomodus for systemgrensesnitt"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 1bbab4ae9736..42abd4439421 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -203,10 +203,10 @@ <string name="face_reenroll_failure_dialog_content" msgid="7073947334397236935">"फेस अनलक सेटअप गर्न सकिएन। फेरि प्रयास गर्न सेटिङमा जानुहोस्।"</string> <string name="fingerprint_dialog_touch_sensor" msgid="2817887108047658975">"फिंगरप्रिन्ट सेन्सरमा छुनुहोस्"</string> <string name="fingerprint_dialog_authenticated_confirmation" msgid="1603899612957562862">"जारी राख्न अनलक आइकनमा थिच्नुहोस्"</string> - <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"अनुहार पहिचान गर्न सकिएन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string> + <string name="fingerprint_dialog_use_fingerprint_instead" msgid="5542430577183894219">"अनुहार मिलेन। बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्।"</string> <!-- no translation found for keyguard_face_failed_use_fp (7140293906176164263) --> <skip /> - <string name="keyguard_face_failed" msgid="2346762871330729634">"अनुहार पहिचान गर्न सकिएन"</string> + <string name="keyguard_face_failed" msgid="2346762871330729634">"अनुहार मिलेन"</string> <string name="keyguard_suggest_fingerprint" msgid="8742015961962702960">"बरु फिंगरप्रिन्ट प्रयोग गर्नुहोस्"</string> <string name="keyguard_face_unlock_unavailable" msgid="1581949044193418736">"फेस अनलक उपलब्ध छैन"</string> <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"ब्लुटुथ जडान भयो।"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"विजेटहरू कस्टमाइज गर्न केही बेरसम्म थिच्नुहोस्"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"विजेटहरू कस्टमाइज गर्नुहोस्"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"अफ गरिएको विजेटको एप जनाउने आइकन"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"विजेट सम्पादन गर्नुहोस्"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"हटाउनुहोस्"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"विजेट हाल्नुहोस्"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"विजेटहरू कस्टमाइज गर्नुहोस्"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"लक स्क्रिनमा भएका विजेटहरू"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"विजेट चयन गर्नुहोस्"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"विजेट हटाउनुहोस्"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"चयन गरिएका विजेटका लागि ठाउँ चयन गर्नुहोस्"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"प्रयोगकर्ता फेर्नुहोस्"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"पुलडाउन मेनु"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"यो सत्रमा भएका सबै एपहरू र डेटा मेटाइने छ।"</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"आउटपुटसम्बन्धी सेटिङमा जानुहोस्"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"भोल्युम स्लाइडरहरू एक्स्पान्ड गरिएका छन्"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"भोल्युम स्लाइडरहरू कोल्याप्स गरिएका छन्"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s म्युट गर्नुहोस्"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s अनम्युट गर्नुहोस्"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> प्ले गरिँदै छ"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"अडियो यसमा प्ले हुने छ"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"कल चलिरहेको छ"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index 1a831ac735f2..c459b93e87cb 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Houd lang ingedrukt om widgets aan te passen"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widgets aanpassen"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"App-icoon voor uitgezette widget"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Widget bewerken"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Verwijderen"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget toevoegen"</string> @@ -619,7 +621,7 @@ <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Ruimtelijke audio"</string> <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Uit"</string> <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Vast"</string> - <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Hoofdbeweging volgen"</string> + <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Hoofdtracking"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Tik om de beltoonmodus te wijzigen"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"geluid uit"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"geluid aanzetten"</string> @@ -629,8 +631,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Uitvoerinstellingen invoeren"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volumeschuifregelaars uitgevouwen"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volumeschuifregelaars samengevouwen"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"geluid van %s uitzetten"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"geluid van %s aanzetten"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> wordt afgespeeld op"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio wordt afgespeeld op"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Bellen actief"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index e64b1b47eaa8..1444e6d69bc3 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -370,7 +370,7 @@ <string name="quick_settings_contrast_high" msgid="656049259587494499">"ଅଧିକ"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"ହିଅରିଂ ଡିଭାଇସଗୁଡ଼ିକ"</string> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"ହିଅରିଂ ଡିଭାଇସଗୁଡ଼ିକ"</string> - <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ନୂଆ ଡିଭାଇସ ପେୟାର କର"</string> + <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"ନୂଆ ଡିଭାଇସ ପେୟାର କରନ୍ତୁ"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"ନୂଆ ଡିଭାଇସ ପେୟାର କରିବାକୁ କ୍ଲିକ କରନ୍ତୁ"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"ପ୍ରିସେଟକୁ ଅପଡେଟ କରାଯାଇପାରିଲା ନାହିଁ"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"ଡିଭାଇସର ମାଇକ୍ରୋଫୋନକୁ ଅନବ୍ଲକ କରିବେ?"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରିବା ପାଇଁ ଅଧିକ ସମୟ ଦବାନ୍ତୁ"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ଅକ୍ଷମ କରାଯାଇଥିବା ୱିଜେଟ ପାଇଁ ଆପ ଆଇକନ"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ୱିଜେଟକୁ ଏଡିଟ କରନ୍ତୁ"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"କାଢ଼ି ଦିଅନ୍ତୁ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ୱିଜେଟ ଯୋଗ କରନ୍ତୁ"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ୱିଜେଟଗୁଡ଼ିକୁ କଷ୍ଟମାଇଜ କରନ୍ତୁ"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ଲକ ସ୍କ୍ରିନରେ ଥିବା ୱିଜେଟଗୁଡ଼ିକ"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ୱିଜେଟ ଚୟନ କରନ୍ତୁ"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ୱିଜେଟକୁ କାଢ଼ି ଦିଅନ୍ତୁ"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"ଚୟନିତ ୱିଜେଟ ରଖନ୍ତୁ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ୟୁଜର୍ ବଦଳାନ୍ତୁ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ପୁଲଡାଉନ ମେନୁ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ଏହି ସେସନର ସମସ୍ତ ଆପ୍ ଓ ଡାଟା ଡିଲିଟ୍ ହୋଇଯିବ।"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ଆଉଟପୁଟ ସେଟିଂସ ଲେଖନ୍ତୁ"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ଭଲ୍ୟୁମ ସ୍ଲାଇଡରଗୁଡ଼ିକୁ ବିସ୍ତାର କରାଯାଇଛି"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ଭଲ୍ୟୁମ ସ୍ଲାଇଡରଗୁଡ଼ିକୁ ସଙ୍କୁଚିତ କରାଯାଇଛି"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%sକୁ ମ୍ୟୁଟ କରନ୍ତୁ"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%sକୁ ଅନମ୍ୟୁଟ କରନ୍ତୁ"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>ରେ ପ୍ଲେ କରାଯାଉଛି"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"ଅଡିଓ ଏଥିରେ ପ୍ଲେ ହେବ"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"କଲ ଚାଲିଛି"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"ସିଷ୍ଟମ୍ UI ଟ୍ୟୁନର୍"</string> <string name="status_bar" msgid="4357390266055077437">"ଷ୍ଟାଟସ୍ ବାର୍"</string> <string name="demo_mode" msgid="263484519766901593">"ସିଷ୍ଟମ୍ UI ଡେମୋ ମୋଡ୍"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 394d790ecbdb..23914b3f16c6 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ਵਿਜੇਟਾਂ ਨੂੰ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਦਬਾਈ ਰੱਖੋ"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ਵਿਜੇਟ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ਬੰਦ ਵਿਜੇਟ ਲਈ ਐਪ ਪ੍ਰਤੀਕ"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ਵਿਜੇਟ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"ਹਟਾਓ"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ਵਿਜੇਟ ਸ਼ਾਮਲ ਕਰੋ"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ਵਿਜੇਟ ਵਿਉਂਤਬੱਧ ਕਰੋ"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਵਿਜੇਟ"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ਵਿਜੇਟ ਚੁਣੋ"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ਵਿਜੇਟ ਹਟਾਓ"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"ਚੁਣੇ ਗਏ ਵਿਜੇਟ ਲਈ ਥਾਂ ਚੁਣੋ"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"ਵਰਤੋਂਕਾਰ ਸਵਿੱਚ ਕਰੋ"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"ਪੁੱਲਡਾਊਨ ਮੀਨੂ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ਇਸ ਸੈਸ਼ਨ ਵਿਚਲੀਆਂ ਸਾਰੀਆਂ ਐਪਾਂ ਅਤੇ ਡਾਟੇ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਜਾਵੇਗਾ।"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ਆਊਟਪੁੱਟ ਸੈਟਿੰਗਾਂ ਦਾਖਲ ਕਰੋ"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ਅਵਾਜ਼ ਸਲਾਈਡਰਾਂ ਵਿਸਤਾਰ ਕੀਤਾ ਗਿਆ"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ਅਵਾਜ਼ ਸਲਾਈਡਰਾਂ ਨੂੰ ਸਮੇਟਿਆ ਗਿਆ"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s ਨੂੰ ਮਿਊਟ ਕਰੋ"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s ਨੂੰ ਅਣਮਿਊਟ ਕਰੋ"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ਚਲਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"ਆਡੀਓ ਇਸ \'ਤੇ ਚੱਲੇਗੀ"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"ਕਾਲ ਜਾਰੀ ਹੈ"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI ਟਿਊਨਰ"</string> <string name="status_bar" msgid="4357390266055077437">"ਸਥਿਤੀ ਪੱਟੀ"</string> <string name="demo_mode" msgid="263484519766901593">"ਸਿਸਟਮ UI ਡੈਮੋ ਮੋਡ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 920862837eb9..4609f08ca0e0 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Przytrzymaj, aby dostosować widżety"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Dostosuj widżety"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacji z wyłączonym widżetem"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Edytuj widżet"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Usuń"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodaj widżet"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Dostosuj widżety"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widżety na ekranie blokady"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"wybierz widżet"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"usuń widżet"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"umieść wybrany widżet"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Przełącz użytkownika"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wszystkie aplikacje i dane w tej sesji zostaną usunięte."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Otwórz ustawienia sygnału wyjściowego"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Suwaki głośności są rozwinięte"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Suwaki głośności są zwinięte"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"wycisz: %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"wyłącz wyciszenie: %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Odtwarzam <xliff:g id="LABEL">%s</xliff:g> na"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Wyjścia dźwięku:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Dzwonię na:"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Kalibrator System UI"</string> <string name="status_bar" msgid="4357390266055077437">"Pasek stanu"</string> <string name="demo_mode" msgid="263484519766901593">"Tryb demonstracyjny interfejsu"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 60472c8bcb34..425fa65b00fc 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícone do app para widget desativado"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets na tela de bloqueio"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"selecionar widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"remover widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"posicionar widget selecionado"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu suspenso"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Inserir configurações de saída"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controles deslizantes de volume abertos"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controles deslizantes de volume fechados"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"desativar o som de %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ativar o som de %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Onde o áudio vai tocar?"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ligando"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string> <string name="status_bar" msgid="4357390266055077437">"Barra de status"</string> <string name="demo_mode" msgid="263484519766901593">"Modo de demonstração da interface do sistema"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 3b9bebb784d8..44531331bd68 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha premido para personalizar os widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícone da app do widget desativado"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets no ecrã de bloqueio"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"selecionar widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"remover widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"posicionar widget selecionado"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Mudar utilizador"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu pendente"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todas as apps e dados desta sessão serão eliminados."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Introduzir definições de saída"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controlos de deslize do volume expandidos"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controlos de deslize do volume reduzidos"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"desativar o som de %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"reativar o som de %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"A ouvir <xliff:g id="LABEL">%s</xliff:g> em:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Áudio ouvido em:"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Chamada em curso"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 60472c8bcb34..425fa65b00fc 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Mantenha pressionado para personalizar widgets"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizar widgets"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ícone do app para widget desativado"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Editar widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Remover"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adicionar widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizar widgets"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgets na tela de bloqueio"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"selecionar widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"remover widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"posicionar widget selecionado"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Trocar usuário"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menu suspenso"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Todos os apps e dados nesta sessão serão excluídos."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Inserir configurações de saída"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Controles deslizantes de volume abertos"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Controles deslizantes de volume fechados"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"desativar o som de %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"ativar o som de %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Tocando <xliff:g id="LABEL">%s</xliff:g> em"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Onde o áudio vai tocar?"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ligando"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizador System UI"</string> <string name="status_bar" msgid="4357390266055077437">"Barra de status"</string> <string name="demo_mode" msgid="263484519766901593">"Modo de demonstração da interface do sistema"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index 84d68e70037c..596349ee57f1 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Apasă lung pentru a personaliza widgeturi"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizează widgeturile"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Pictograma aplicației pentru widgetul dezactivat"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Editează widgetul"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Elimină"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Adaugă un widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizează widgeturile"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgeturi pe ecranul de blocare"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"selectează un widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"elimină widgetul"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"plasează widgetul selectat"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Schimbă utilizatorul"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"meniu vertical"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Toate aplicațiile și datele din această sesiune vor fi șterse."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Introdu setările de ieșire"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Glisoare de volum extinse"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Glisoare de volum restrânse"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"dezactivează sunetul pentru %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"activează sunetul pentru %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Se redă <xliff:g id="LABEL">%s</xliff:g> pe"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Conținutul audio se va reda pe"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Apel în curs pe"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Bară de stare"</string> <string name="demo_mode" msgid="263484519766901593">"Mod demonstrativ pentru IU sistem"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index c405469371da..6fabeae41a4a 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Нажмите и удерживайте, чтобы настроить виджеты."</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Настроить виджеты"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Значок приложения для отключенного виджета"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Изменить виджет"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Удалить"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Добавить виджет"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Настроить виджеты"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Виджеты на заблокированном экране"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"выбрать виджет"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"удалить виджет"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"разместить выбранный виджет"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Сменить пользователя."</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"раскрывающееся меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Все приложения и данные этого профиля будут удалены."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Перейти к настройкам вывода аудио"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Ползунки для регулировки громкости развернуты"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Ползунки для регулировки громкости свернуты"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"отключить звук: %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"включить звук: %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> – запущено здесь:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Проигрывание аудио:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Настройки вызова"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Строка состояния"</string> <string name="demo_mode" msgid="263484519766901593">"Интерфейс системы: деморежим"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 37bb23ac64a7..238e6c8e2b80 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"විජට් අභිරුචිකරණය කිරීමට දිගු ඔබන්න"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"විජට්ටු අභිරුචි කරන්න"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"අබල කළ විජට් සඳහා යෙදුම් නිරූපකය"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"විජට්ටු සංස්කරණ කරන්න"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"ඉවත් කරන්න"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"විජට්ටුව එක් කරන්න"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"විජට්ටු අභිරුචි කරන්න"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"අගුළු තිරයෙහි විජට්"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"විජට්ටුව තෝරන්න"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"විජට්ටුව ඉවත් කරන්න"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"තෝරන ලද විජට්ටුව තබන්න"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"පරිශීලක මාරුව"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"නිපතන මෙනුව"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"මෙම සැසියේ සියළුම යෙදුම් සහ දත්ත මකාවී."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"ප්රතිදාන සැකසීම් ඇතුල් කරන්න"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"හඬ ස්ලයිඩර දිගහැර ඇත"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"හඬ ස්ලයිඩර හකුළා ඇත"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s නිහඬ කරන්න"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s නිහඬ නොකරන්න"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> වාදනය කරන්නේ"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"ශ්රව්ය වාදනය වනු ඇත්තේ"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"ඇමතීම"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"පද්ධති UI සුසරකය"</string> <string name="status_bar" msgid="4357390266055077437">"තත්ත්ව තීරුව"</string> <string name="demo_mode" msgid="263484519766901593">"පද්ධති UI ආදර්ශන ප්රකාරය"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 675a34522086..825dba620870 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -269,7 +269,7 @@ <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Klepnutím pripojíte alebo odpojíte zariadenie"</string> <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Spárovať nové zariadenie"</string> <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Zobraziť všetko"</string> - <string name="turn_on_bluetooth" msgid="5681370462180289071">"Použiť Bluetooth"</string> + <string name="turn_on_bluetooth" msgid="5681370462180289071">"Používať Bluetooth"</string> <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Pripojené"</string> <string name="quick_settings_bluetooth_device_audio_sharing" msgid="1496358082943301670">"Zdieľanie zvuku"</string> <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"Uložené"</string> @@ -370,7 +370,7 @@ <string name="quick_settings_contrast_high" msgid="656049259587494499">"Vysoký"</string> <string name="quick_settings_hearing_devices_label" msgid="7277170419679404129">"Načúvacie zariadenia"</string> <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Načúvacie zariadenia"</string> - <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Párovanie nového zariadenia"</string> + <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Spárovať nové zariadenie"</string> <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Kliknutím spárujete nové zariadenie"</string> <string name="hearing_devices_presets_error" msgid="350363093458408536">"Predvoľbu sa nepodarilo aktualizovať"</string> <string name="sensor_privacy_start_use_mic_dialog_title" msgid="563796653825944944">"Chcete odblokovať mikrofón zariadenia?"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Miniaplikácie prispôsobíte dlhým stlačením"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prispôsobiť miniaplikácie"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona deaktivovanej miniaplikácie"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Upraviť miniaplikáciu"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrániť"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Pridať miniaplikáciu"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Prispôsobiť miniaplikácie"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Miniaplikácie na uzamknutej obrazovke"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vybrať miniaplikáciu"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"odstrániť miniaplikáciu"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"prepnúť vybranú miniaplikáciu"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Prepnutie používateľa"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rozbaľovacia ponuka"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Všetky aplikácie a údaje v tejto relácii budú odstránené."</string> @@ -619,7 +619,7 @@ <string name="volume_panel_spatial_audio_title" msgid="3367048857932040660">"Priestorový zvuk"</string> <string name="volume_panel_spatial_audio_off" msgid="4177490084606772989">"Vypnuté"</string> <string name="volume_panel_spatial_audio_fixed" msgid="3136080137827746046">"Pevné"</string> - <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Sled. pohybov hlavy"</string> + <string name="volume_panel_spatial_audio_tracking" msgid="5711115234001762974">"Sled. polohy hlavy"</string> <string name="volume_ringer_change" msgid="3574969197796055532">"Režim zvonenia zmeníte klepnutím"</string> <string name="volume_ringer_hint_mute" msgid="4263821214125126614">"vypnite zvuk"</string> <string name="volume_ringer_hint_unmute" msgid="6119086890306456976">"zapnite zvuk"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Zadať nastavenia výstupu"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Posúvače hlasitosti sú rozbalené"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Posúvače hlasitosti sú zbalené"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"vypnete zvuk %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"zapnete zvuk %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> sa prehráva v:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvuk sa prehrá cez"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Volanie je zapnuté"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Tuner používateľského rozhrania systému"</string> <string name="status_bar" msgid="4357390266055077437">"Stavový riadok"</string> <string name="demo_mode" msgid="263484519766901593">"Ukážka používateľského rozhrania systému"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index f97d6624c00c..82f2df73a355 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pridržite za prilagajanje pripomočkov"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Prilagajanje pripomočkov"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona aplikacije za onemogočen pripomoček"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Urejanje pripomočka"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Odstrani"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Dodajanje pripomočka"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Prilagajanje pripomočkov"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Pripomočki na zaklenjenem zaslonu"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"izberite pripomoček"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"odstranitev pripomočka"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"postavitev izbranega pripomočka"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Preklop med uporabniki"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"spustni meni"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Vse aplikacije in podatki v tej seji bodo izbrisani."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Vnos izhodnih nastavitev"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Razširitev drsnikov za glasnost"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Strnitev drsnikov za glasnost"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"izklop zvoka %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"vklop zvoka %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Predvajanje »<xliff:g id="LABEL">%s</xliff:g>« v"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Zvok bo predvajan v"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Poteka klicanje"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Uglaševalnik uporabniškega vmesnika sistema"</string> <string name="status_bar" msgid="4357390266055077437">"Vrstica stanja"</string> <string name="demo_mode" msgid="263484519766901593">"Predstavitveni način uporabniškega vmesnika sistema"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index b638198c6d5f..af2e3c788b5b 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Shtyp gjatë për të personalizuar miniaplikacionet"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Personalizo miniaplikacionet"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Ikona e aplikacionit për miniaplikacionin e çaktivizuar"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Modifiko miniaplikacionin"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Hiq"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Shto miniaplikacionin"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Personalizo miniaplikacionet"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Miniaplikacionet në ekranin e kyçjes"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"zgjidh miniaplikacionin"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"hiq miniaplikacionin"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"vendos miniaplikacionin e zgjedhur"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Ndërro përdorues"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyja me tërheqje poshtë"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Të gjitha aplikacionet dhe të dhënat në këtë sesion do të fshihen."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Hyr te cilësimet e daljes"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Rrëshqitësit e volumit u zgjeruan"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Rrëshqitësit e volumit u palosën"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"çaktivizo audion: %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"aktivizo audion: %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Po luhet <xliff:g id="LABEL">%s</xliff:g> te"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Do të luhet audio te"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Telefonatë aktive"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Sintonizuesi i Sistemit të Ndërfaqes së Përdoruesit"</string> <string name="status_bar" msgid="4357390266055077437">"Shiriti i statusit"</string> <string name="demo_mode" msgid="263484519766901593">"Modaliteti i demonstrimit i ndërfaqes së përdoruesit të sistemit"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 4cc1134a369a..42b979c0add9 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Дуги притисак за прилагођавање виџета"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Прилагоди виџете"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Икона апликације за онемогућен виџет"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Измени виџет"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Уклони"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додај виџет"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Прилагодите виџете"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Виџети на закључаном екрану"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"изаберите виџет"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"уклоните виџет"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"поставите изабрани виџет"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Замени корисника"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"падајући мени"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Све апликације и подаци у овој сесији ће бити избрисани."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Унесите подешавања излазног сигнала"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Клизачи за јачину звука су проширени"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Клизачи за јачину звука су скупљени"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"искључите звук за: %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"укључите звук за: %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> се пушта на"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Звук се пушта на"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Позив на уређају"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Тјунер за кориснички интерфејс система"</string> <string name="status_bar" msgid="4357390266055077437">"Статусна трака"</string> <string name="demo_mode" msgid="263484519766901593">"Режим демонстрације за кориснички интерфејс система"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index b0ce12f8e5a2..29dca4630df8 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Tryck länge för att anpassa widgetar"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Anpassa widgetar"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Appikon för inaktiverad widget"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Redigera widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Ta bort"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Lägg till widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Anpassa widgetar"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Widgetar på låsskärmen"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"välj widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ta bort widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"placera vald widget"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Byt användare"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"rullgardinsmeny"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Alla appar och data i denna session kommer att raderas."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Ange inställningar för utdata"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Volymreglagen har utökats"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Volymreglagen har komprimerats"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"stäng av ljudet för %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"slå på ljudet för %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Spelar upp <xliff:g id="LABEL">%s</xliff:g> på"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Ljud spelas upp på"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Samtal på"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Inställningar för systemgränssnitt"</string> <string name="status_bar" msgid="4357390266055077437">"Statusfält"</string> <string name="demo_mode" msgid="263484519766901593">"Demoläge för systemgränssnitt"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 8dc22a785069..9d5181e21b45 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Bonyeza kwa muda mrefu uweke mapendeleo ya wijeti"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Badilisha wijeti upendavyo"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Aikoni ya programu ya wijeti iliyozimwa"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Badilisha wijeti"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Ondoa"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Ongeza wijeti"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Badilisha wijeti upendavyo"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Wijeti kwenye skrini iliyofungwa"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"chagua wijeti"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ondoa wijeti"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"weka wijeti uliyochagua"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Badili mtumiaji"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"menyu ya kuvuta chini"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Data na programu zote katika kipindi hiki zitafutwa."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Weka mipangilio ya sauti inayotoka"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Vitelezi vya sauti vimepanuliwa"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Vitelezi vya kiwango cha sauti vimekunjwa"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"zima sauti ya %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"rejesha sauti ya %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Inacheza <xliff:g id="LABEL">%s</xliff:g> kwenye"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Sauti itacheza kwenye"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Simu inaendelea"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Kirekebishi cha kiolesura cha mfumo"</string> <string name="status_bar" msgid="4357390266055077437">"Sehemu ya kuonyesha hali"</string> <string name="demo_mode" msgid="263484519766901593">"Hali ya onyesho la kirekebishi cha kiolesura cha mfumo"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index ee86acac2d7e..a2f4ce5424a2 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -275,7 +275,7 @@ <string name="quick_settings_bluetooth_device_saved" msgid="7549938728928069477">"சேமிக்கப்பட்டது"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_disconnect" msgid="415980329093277342">"இணைப்பு நீக்கும்"</string> <string name="accessibility_quick_settings_bluetooth_device_tap_to_activate" msgid="3724301751036877403">"செயல்படுத்தும்"</string> - <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"நாளைக்குத் தானாகவே மீண்டும் இயக்கப்படும்"</string> + <string name="turn_on_bluetooth_auto_tomorrow" msgid="414836329962473906">"நாளைக்குத் தானாகவே மீண்டும் இயக்கப்படுதல்"</string> <string name="turn_on_bluetooth_auto_info_disabled" msgid="682984290339848844">"விரைவுப் பகிர்தல், Find My Device போன்ற அம்சங்கள் புளூடூத்தைப் பயன்படுத்துகின்றன"</string> <string name="turn_on_bluetooth_auto_info_enabled" msgid="7440944034584560279">"நாளை காலை புளூடூத் இயக்கப்படும்"</string> <string name="quick_settings_bluetooth_audio_sharing_button" msgid="4499275822759907822">"ஆடியோ பகிர்வு"</string> @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"விட்ஜெட்களைப் பிரத்தியேகமாக்க நீண்ட நேரம் அழுத்துக"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"விட்ஜெட்களைப் பிரத்தியேகமாக்குங்கள்"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"முடக்கப்பட்ட விட்ஜெட்டுக்கான ஆப்ஸ் ஐகான்"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"விட்ஜெட்டைத் திருத்து"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"அகற்றும்"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"விட்ஜெட்டைச் சேர்"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"விட்ஜெட்களைப் பிரத்தியேகமாக்கும்"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"பூட்டுத் திரையில் விட்ஜெட்கள்"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"விட்ஜெட்டைத் தேர்ந்தெடுக்கும்"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"விட்ஜெட்டை அகற்றும்"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"தேர்ந்தெடுத்த விட்ஜெட்டைக் காட்சிப்படுத்தும்"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"பயனரை மாற்று"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"கீழ் இழுக்கும் மெனு"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"இந்த அமர்வின் எல்லா ஆப்ஸும் தரவும் நீக்கப்படும்."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"வெளியீட்டு அமைப்புகளுக்குச் செல்லும்"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ஒலியளவு ஸ்லைடர்கள் விரிவாக்கப்பட்டன"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ஒலியளவு ஸ்லைடர்கள் சுருக்கப்பட்டன"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s ஐ ஒலியடக்கும்"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s ஐ ஒலி இயக்கும்"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"இதில் <xliff:g id="LABEL">%s</xliff:g> பிளே ஆகிறது"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"ஆடியோ இதில் பிளே ஆகும்"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"அழைப்பில் உள்ளது"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"நிலைப் பட்டி"</string> <string name="demo_mode" msgid="263484519766901593">"சிஸ்டம் பயனர் இடைமுக டெமோ பயன்முறை"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index d8622a3d9fc1..5b703a0d96fc 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"విడ్జెట్లను అనుకూలీకరించడానికి, నొక్కి, ఉంచండి"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"విడ్జెట్లను అనుకూలంగా మార్చండి"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"డిజేబుల్ చేయబడిన విడ్జెట్ కోసం యాప్ చిహ్నం"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"విడ్జెట్ను ఎడిట్ చేయండి"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"తీసివేయండి"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"విడ్జెట్ను జోడించండి"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"విడ్జెట్లను అనుకూలంగా మార్చండి"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"లాక్ స్క్రీన్లో విడ్జెట్లు"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"విడ్జెట్ను ఎంచుకోండి"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"విడ్జెట్ను తీసివేయండి"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"ఎంచుకున్న విడ్జెట్ కోసం ప్లేస్ను ఎంచుకోండి"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"వినియోగదారుని మార్చు"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"పుల్డౌన్ మెనూ"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ఈ సెషన్లోని అన్ని యాప్లు మరియు డేటా తొలగించబడతాయి."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"అవుట్పుట్ సెట్టింగ్లను ఎంటర్ చేయండి"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"వాల్యూమ్ స్లయిడర్లు విస్తరించబడ్డాయి"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"వాల్యూమ్ స్లయిడర్లు కుదించబడ్డాయి"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%sను మ్యూట్ చేయండి"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%sను అన్మ్యూట్ చేయండి"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> ప్లే అయ్యే డివైజ్"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"ఆడియో ప్లే డివైజ్"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"కాల్ ప్రోగ్రెస్లో ఉంది"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"సిస్టమ్ UI ట్యూనర్"</string> <string name="status_bar" msgid="4357390266055077437">"స్టేటస్ బార్"</string> <string name="demo_mode" msgid="263484519766901593">"సిస్టమ్ UI డెమో మోడ్"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 9f09b9ccdfe4..73ca20004444 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"กดค้างเพื่อปรับแต่งวิดเจ็ต"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ปรับแต่งวิดเจ็ต"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"ไอคอนแอปสำหรับวิดเจ็ตที่ปิดใช้อยู่"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"แก้ไขวิดเจ็ต"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"นำออก"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"เพิ่มวิดเจ็ต"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ปรับแต่งวิดเจ็ต"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"วิดเจ็ตในหน้าจอล็อก"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"เลือกวิดเจ็ต"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"นำวิดเจ็ตออก"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"จัดวางวิดเจ็ตที่เลือก"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"สลับผู้ใช้"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"เมนูแบบเลื่อนลง"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"ระบบจะลบแอปและข้อมูลทั้งหมดในเซสชันนี้"</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"เข้าสู่การตั้งค่าเอาต์พุต"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"ขยายแถบเลื่อนระดับเสียงแล้ว"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"ยุบแถบเลื่อนระดับเสียงแล้ว"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"ปิดเสียง%s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"เปิดเสียง%s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"กำลังเล่น <xliff:g id="LABEL">%s</xliff:g> ใน"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"เสียงจะเล่นต่อใน"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"กำลังโทรติดต่อ"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 9122627107f4..0c616fa91dc1 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Pindutin nang matagal para i-customize ang mga widget"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"I-customize ang mga widget"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Icon ng app para sa na-disable na widget"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"I-edit ang widget"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Alisin"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Magdagdag ng widget"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"I-customize ang mga widget"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Mga widget sa lock screen"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"pumili ng widget"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"alisin ang widget"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"ilagay ang napiling widget"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Magpalit ng user"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"pulldown menu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ide-delete ang lahat ng app at data sa session na ito."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Pumunta sa mga setting ng output"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Na-expand ang mga slider ng volume"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Na-collapse ang mga slider ng volume"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"i-mute ang %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"i-unmute ang %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Nagpe-play ang <xliff:g id="LABEL">%s</xliff:g> sa"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"I-play ang audio sa"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Tumatawag sa"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 1f7a8e0b4ca4..6723c4226f04 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Widget\'ları özelleştirmek için uzun basın"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Widget\'ları özelleştir"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Devre dışı bırakılan widget\'ın uygulama simgesi"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Widget\'ı düzenle"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Kaldır"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Widget ekle"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Widget\'ları özelleştir"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Kilit ekranındaki widget\'lar"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"widget seçin"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"widget\'ı kaldır"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"seçilen widget\'ı yerleştir"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Kullanıcı değiştirme"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"açılır menü"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Bu oturumdaki tüm uygulamalar ve veriler silinecek."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Çıkış ayarlarını gir"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Ses seviyesi kaydırma çubukları genişletildi"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Ses seviyesi kaydırma çubukları daraltıldı"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s sesini kapatma"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s sesini açma"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> şurada çalacak:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Ses şurada çalacak:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Şu cihaz aranıyor:"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Sistem Arayüzü Ayarlayıcısı"</string> <string name="status_bar" msgid="4357390266055077437">"Durum çubuğu"</string> <string name="demo_mode" msgid="263484519766901593">"Sistem kullanıcı arayüzü demo modu"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index e9b45bf14e99..2659f9fedfee 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Утримуйте, щоб налаштувати віджети"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Налаштувати віджети"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Значок додатка для вимкненого віджета"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Редагувати віджет"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Видалити"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Додати віджет"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Налаштувати віджети"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Віджети на заблокованому екрані"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"виберіть віджет"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"видалити віджет"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"розмістити вибраний віджет"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Змінити користувача"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"спадне меню"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Усі додатки й дані з цього сеансу буде видалено."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Відкрити налаштування відтворення"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Повзунки гучності розгорнуто"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Повзунки гучності згорнуто"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"вимкнути звук %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"увімкнути звук %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Де відтворюється <xliff:g id="LABEL">%s</xliff:g>:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Де гратиме аудіо:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Триває виклик"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"System UI Tuner"</string> <string name="status_bar" msgid="4357390266055077437">"Рядок стану"</string> <string name="demo_mode" msgid="263484519766901593">"Демо-режим інтерфейсу системи"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index f9fc9f0de389..2a7fda1791e5 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"ویجٹس کو حسب ضرورت بنانے کے لیے لانگ پریس کریں"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"ویجیٹس کو حسب ضرورت بنائیں"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"غیر فعال ویجیٹ کے لئے ایپ آئیکن"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"ویجیٹ میں ترمیم کریں"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"ہٹائیں"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"ویجیٹ شامل کریں"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"ویجیٹس کو حسب ضرورت بنائیں"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"مقفل اسکرین پر ویجیٹس"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"ویجیٹ منتخب کریں"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"ویجیٹ ہٹائیں"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"منتخب ویجیٹ رکھیں"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"صارف سوئچ کریں"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"پل ڈاؤن مینیو"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"اس سیشن میں موجود سبھی ایپس اور ڈیٹا کو حذف کر دیا جائے گا۔"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"آؤٹ پٹ کی ترتیبات درج کریں"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"والیوم سلائیڈرز کو پھیلا دیا گیا"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"والیوم سلائیڈرز سکیڑا گیا"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%s خاموش کریں"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s غیر خاموش کریں"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> پر چل رہی ہے"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"آڈیو اس پر چلے گی"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"کال کی جا رہی ہے"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"سسٹم UI ٹیونر"</string> <string name="status_bar" msgid="4357390266055077437">"اسٹیٹس بار"</string> <string name="demo_mode" msgid="263484519766901593">"سسٹم UI ڈیمو موڈ"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 60baeec4ed84..0d7709c51775 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Vidjetlarni sozlash uchun bosib turing"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Vidjetlarni moslashtirish"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Faolsizlantirilgan vidjet uchun ilova belgisi"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Vidjetni tahrirlash"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Olib tashlash"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Vidjet kiritish"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Vidjetlarni moslash"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Ekran qulfidagi vidjetlar"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"vidjet tanlash"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"vidjetni olib tashlash"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"tanlangan vidjetni joylash"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Foydalanuvchini almashtirish"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"tortib tushiriladigan menyu"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Ushbu seansdagi barcha ilovalar va ma’lumotlar o‘chirib tashlanadi."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Chiqarish sozlamalarini kiritish"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Tovush slayderlari yoyilgan"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Tovush slayderlari yigʻilgan"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"%sni ovozsiz qilish"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"%s ovozini chiqarish"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>da ijro etilmoqda"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Audio ijro etiladi"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Chaqiruv yoniq"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 9656eb3cf81e..2ddcd6d32f44 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Nhấn và giữ để tuỳ chỉnh tiện ích"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Tuỳ chỉnh tiện ích"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Biểu tượng ứng dụng của tiện ích đã bị vô hiệu hoá"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Chỉnh sửa tiện ích"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Xoá"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Thêm tiện ích"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Tuỳ chỉnh tiện ích"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Các tiện ích trên màn hình khoá"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"chọn tiện ích"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"xoá tiện ích"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"đặt tiện ích đã chọn vào vị trí"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Chuyển đổi người dùng"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"trình đơn kéo xuống"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Tất cả ứng dụng và dữ liệu trong phiên này sẽ bị xóa."</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Mở phần cài đặt thiết bị đầu ra"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Đã mở rộng thanh trượt âm lượng"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Đã thu gọn thanh trượt âm lượng"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"tắt tiếng %s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"bật tiếng %s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Đang phát <xliff:g id="LABEL">%s</xliff:g> trên"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Âm thanh sẽ phát trên"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Đang gọi điện"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"Bộ điều hướng giao diện người dùng hệ thống"</string> <string name="status_bar" msgid="4357390266055077437">"Thanh trạng thái"</string> <string name="demo_mode" msgid="263484519766901593">"Chế độ thử nghiệm giao diện người dùng hệ thống"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 6f1a0bd0bc7b..64e37ce4b88d 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"长按即可自定义微件"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自定义微件"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"已停用微件的应用图标"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"修改微件"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"添加微件"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"自定义微件"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"锁定屏幕上的微件"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"选择微件"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"移除微件"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"放置所选微件"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切换用户"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉菜单"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"此会话中的所有应用和数据都将被删除。"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"进入输出设置"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"音量滑块已展开"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"音量滑块已收起"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"静音“%s”"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"取消静音“%s”"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g>播放位置:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"音频播放位置:"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"正在通话"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"系统界面调节工具"</string> <string name="status_bar" msgid="4357390266055077437">"状态栏"</string> <string name="demo_mode" msgid="263484519766901593">"系统界面演示模式"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 47d0692c3d84..714e479cb515 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自訂小工具"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"已停用小工具的應用程式圖示"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"編輯小工具"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"自訂小工具"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"上鎖畫面上的小工具"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"揀小工具"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"移除小工具"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"放置所選小工具"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會被刪除。"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"輸入輸出設定"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"打開咗音量滑桿"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"閂埋咗音量滑桿"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"將%s設定為靜音"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"取消%s的靜音設定"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"正在播放「<xliff:g id="LABEL">%s</xliff:g>」的裝置:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"音訊播放媒體"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"通話中"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"系統使用者介面調諧器"</string> <string name="status_bar" msgid="4357390266055077437">"狀態列"</string> <string name="demo_mode" msgid="263484519766901593">"系統使用者介面示範模式"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index b3ed7a051bc0..495a055c3e70 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"長按即可自訂小工具"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"自訂小工具"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"所停用小工具的應用程式圖示"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"編輯小工具"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"移除"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"新增小工具"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"自訂小工具"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"螢幕鎖定畫面上的小工具"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"選取小工具"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"移除小工具"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"放置所選小工具"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"切換使用者"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"下拉式選單"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"這個工作階段中的所有應用程式和資料都會刪除。"</string> @@ -629,12 +629,17 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"進入輸出設定"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"音量滑桿已展開"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"音量滑桿已收合"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"將%s設為靜音"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"將%s取消靜音"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"正在播放「<xliff:g id="LABEL">%s</xliff:g>」的裝置:"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"音訊播放位置"</string> - <!-- no translation found for media_output_title_ongoing_call (208426888064112006) --> - <skip /> + <string name="media_output_title_ongoing_call" msgid="208426888064112006">"通話中"</string> <string name="system_ui_tuner" msgid="1471348823289954729">"系統使用者介面調整精靈"</string> <string name="status_bar" msgid="4357390266055077437">"狀態列"</string> <string name="demo_mode" msgid="263484519766901593">"系統 UI 展示模式"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 6e9e08b63095..f5ee5a0d60b1 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -447,6 +447,8 @@ <string name="popup_on_dismiss_cta_tile_text" msgid="8292501780996070019">"Cindezela isikhathi eside ukuze wenze ngokwezifiso amawijethi"</string> <string name="button_to_configure_widgets_text" msgid="4191862850185256901">"Yenza ngokwezifiso amawijethi"</string> <string name="icon_description_for_disabled_widget" msgid="4693151565003206943">"Isithonjana se-app sewijethi evaliwe"</string> + <!-- no translation found for icon_description_for_pending_widget (8413816401868001755) --> + <skip /> <string name="edit_widget" msgid="9030848101135393954">"Hlela amawijethi"</string> <string name="button_to_remove_widget" msgid="3948204829181214098">"Susa"</string> <string name="hub_mode_add_widget_button_text" msgid="4831464661209971729">"Engeza iwijethi"</string> @@ -461,10 +463,8 @@ <string name="accessibility_action_label_edit_widgets" msgid="3821868581348322346">"Yenza ngokwezifiso amawijethi"</string> <string name="accessibility_content_description_for_communal_hub" msgid="1670220840599380118">"Amawijethi ekukhiyeni isikrini"</string> <string name="accessibility_action_label_select_widget" msgid="8897281501387398191">"khetha iwijethi"</string> - <!-- no translation found for accessibility_action_label_remove_widget (3373779447448758070) --> - <skip /> - <!-- no translation found for accessibility_action_label_place_widget (1914197458644168978) --> - <skip /> + <string name="accessibility_action_label_remove_widget" msgid="3373779447448758070">"susa iwijethi"</string> + <string name="accessibility_action_label_place_widget" msgid="1914197458644168978">"beka iwijethi ekhethiwe"</string> <string name="accessibility_multi_user_switch_switcher" msgid="5330448341251092660">"Shintsha umsebenzisi"</string> <string name="accessibility_multi_user_list_switcher" msgid="8574105376229857407">"imenyu yokudonsela phansi"</string> <string name="guest_exit_guest_dialog_message" msgid="8183450985628495709">"Wonke ama-app nedatha kulesi sikhathi azosuswa."</string> @@ -629,8 +629,14 @@ <string name="volume_panel_enter_media_output_settings" msgid="8824244246272552669">"Faka amasethingi wokuphumayo"</string> <string name="volume_panel_expanded_sliders" msgid="1885750987768506271">"Izilayidi zevolumu zinwetshiwe"</string> <string name="volume_panel_collapsed_sliders" msgid="1413383759434791450">"Izilayidi zevolumu zigoqiwe"</string> - <string name="volume_panel_hint_mute" msgid="6962563028495243738">"thulisa i-%s"</string> - <string name="volume_panel_hint_unmute" msgid="7489063242934477382">"susa ukuthula kwe-%s"</string> + <!-- no translation found for volume_panel_hint_mute (2153922288568199077) --> + <skip /> + <!-- no translation found for volume_panel_hint_unmute (4831850937582282340) --> + <skip /> + <!-- no translation found for volume_panel_hint_muted (1124844870181285320) --> + <skip /> + <!-- no translation found for volume_panel_hint_vibrate (4136223145435914132) --> + <skip /> <string name="media_output_label_title" msgid="872824698593182505">"Idlala ku-<xliff:g id="LABEL">%s</xliff:g>"</string> <string name="media_output_title_without_playing" msgid="3825663683169305013">"Umsindo uzodlala"</string> <string name="media_output_title_ongoing_call" msgid="208426888064112006">"Ifonela kokuthi"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 5857692cdaa9..517b44f455d7 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -449,6 +449,8 @@ <dimen name="overlay_preview_container_margin">8dp</dimen> <dimen name="overlay_action_container_margin_horizontal">8dp</dimen> <dimen name="overlay_action_container_margin_bottom">6dp</dimen> + <!-- minimum distance to the left, right or bottom edges. --> + <dimen name="overlay_action_container_minimum_edge_spacing">12dp</dimen> <dimen name="overlay_bg_protection_height">242dp</dimen> <dimen name="overlay_action_container_corner_radius">20dp</dimen> <dimen name="overlay_action_container_padding_vertical">8dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index b5ec5b285486..aecc9066b552 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -384,6 +384,8 @@ <!-- Content description for the app logo icon on biometric prompt. [CHAR LIMIT=NONE] --> <string name="biometric_dialog_logo">App logo</string> + <!-- List of packages for which we want to show overridden logo. For example, an app overrides its launcher logo, if it's in this array, biometric dialog shows the overridden logo; otherwise biometric dialog still shows the default application info icon. [CHAR LIMIT=NONE] --> + <string-array name="biometric_dialog_package_names_for_logo_with_overrides" /> <!-- Message shown when a biometric is authenticated, asking the user to confirm authentication [CHAR LIMIT=30] --> <string name="biometric_dialog_confirm">Confirm</string> <!-- Button name on BiometricPrompt shown when a biometric is detected but not authenticated. Tapping the button resumes authentication [CHAR LIMIT=30] --> diff --git a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt index 87829621f57d..b99c51489521 100644 --- a/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt +++ b/packages/SystemUI/shared/biometrics/src/com/android/systemui/biometrics/shared/model/PromptKind.kt @@ -20,10 +20,11 @@ sealed interface PromptKind { object None : PromptKind data class Biometric( + /** The available modalities for the authentication on the prompt. */ val activeModalities: BiometricModalities = BiometricModalities(), // TODO(b/330908557): Use this value to decide whether to show two pane layout, instead of // simply depending on rotations. - val showTwoPane: Boolean = false + val showTwoPane: Boolean = false, ) : PromptKind object Pin : PromptKind diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl index d191a3c3f28b..d5bc10a322d4 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl @@ -65,7 +65,7 @@ oneway interface IOverviewProxy { /** * Sent when some system ui state changes. */ - void onSystemUiStateChanged(int stateFlags) = 16; + void onSystemUiStateChanged(long stateFlags) = 16; /** * Sent when suggested rotation button could be shown diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index 94b6fd42f701..090033d41ffa 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -162,5 +162,10 @@ interface ISystemUiProxy { oneway void setOverrideHomeButtonLongPress(long duration, float slopMultiplier, boolean haptic) = 55; - // Next id = 56 + /** + * Notifies to toggle quick settings panel. + */ + oneway void toggleQuickSettingsPanel() = 56; + + // Next id = 57 } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java index 69aa90996946..b4377eae4d1f 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java @@ -22,7 +22,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static com.android.systemui.shared.Flags.shadeAllowBackGesture; -import android.annotation.IntDef; +import android.annotation.LongDef; import android.content.Context; import android.content.res.Resources; import android.view.ViewConfiguration; @@ -51,92 +51,94 @@ public class QuickStepContract { // Overview is disabled, either because the device is in lock task mode, or because the device // policy has disabled the feature - public static final int SYSUI_STATE_SCREEN_PINNING = 1 << 0; + public static final long SYSUI_STATE_SCREEN_PINNING = 1L << 0; // The navigation bar is hidden due to immersive mode - public static final int SYSUI_STATE_NAV_BAR_HIDDEN = 1 << 1; + public static final long SYSUI_STATE_NAV_BAR_HIDDEN = 1L << 1; // The notification panel is expanded and interactive (either locked or unlocked), and the // quick settings is not expanded - public static final int SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED = 1 << 2; + public static final long SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED = 1L << 2; // The keyguard bouncer is showing - public static final int SYSUI_STATE_BOUNCER_SHOWING = 1 << 3; + public static final long SYSUI_STATE_BOUNCER_SHOWING = 1L << 3; // The navigation bar a11y button should be shown - public static final int SYSUI_STATE_A11Y_BUTTON_CLICKABLE = 1 << 4; + public static final long SYSUI_STATE_A11Y_BUTTON_CLICKABLE = 1L << 4; // The navigation bar a11y button shortcut is available - public static final int SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE = 1 << 5; + public static final long SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE = 1L << 5; // The keyguard is showing and not occluded - public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING = 1 << 6; + public static final long SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING = 1L << 6; // The recents feature is disabled (either by SUW/SysUI/device policy) - public static final int SYSUI_STATE_OVERVIEW_DISABLED = 1 << 7; + public static final long SYSUI_STATE_OVERVIEW_DISABLED = 1L << 7; // The home feature is disabled (either by SUW/SysUI/device policy) - public static final int SYSUI_STATE_HOME_DISABLED = 1 << 8; + public static final long SYSUI_STATE_HOME_DISABLED = 1L << 8; // The keyguard is showing, but occluded - public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED = 1 << 9; + public static final long SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED = 1L << 9; // The search feature is disabled (either by SUW/SysUI/device policy) - public static final int SYSUI_STATE_SEARCH_DISABLED = 1 << 10; + public static final long SYSUI_STATE_SEARCH_DISABLED = 1L << 10; // The notification panel is expanded and interactive (either locked or unlocked), and quick // settings is expanded. - public static final int SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1 << 11; + public static final long SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1L << 11; // Winscope tracing is enabled - public static final int SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION = 1 << 12; + public static final long SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION = 1L << 12; // The Assistant gesture should be constrained. It is up to the launcher implementation to // decide how to constrain it - public static final int SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED = 1 << 13; + public static final long SYSUI_STATE_ASSIST_GESTURE_CONSTRAINED = 1L << 13; // The bubble stack is expanded. This means that the home gesture should be ignored, since a // swipe up is an attempt to close the bubble stack, but that the back gesture should remain // enabled (since it's used to navigate back within the bubbled app, or to collapse the bubble // stack. - public static final int SYSUI_STATE_BUBBLES_EXPANDED = 1 << 14; + public static final long SYSUI_STATE_BUBBLES_EXPANDED = 1L << 14; // A SysUI dialog is showing. - public static final int SYSUI_STATE_DIALOG_SHOWING = 1 << 15; + public static final long SYSUI_STATE_DIALOG_SHOWING = 1L << 15; // The one-handed mode is active - public static final int SYSUI_STATE_ONE_HANDED_ACTIVE = 1 << 16; + public static final long SYSUI_STATE_ONE_HANDED_ACTIVE = 1L << 16; // Allow system gesture no matter the system bar(s) is visible or not - public static final int SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY = 1 << 17; + public static final long SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY = 1L << 17; // The IME is showing - public static final int SYSUI_STATE_IME_SHOWING = 1 << 18; + public static final long SYSUI_STATE_IME_SHOWING = 1L << 18; // The window magnification is overlapped with system gesture insets at the bottom. - public static final int SYSUI_STATE_MAGNIFICATION_OVERLAP = 1 << 19; + public static final long SYSUI_STATE_MAGNIFICATION_OVERLAP = 1L << 19; // ImeSwitcher is showing - public static final int SYSUI_STATE_IME_SWITCHER_SHOWING = 1 << 20; + public static final long SYSUI_STATE_IME_SWITCHER_SHOWING = 1L << 20; // Device dozing/AOD state - public static final int SYSUI_STATE_DEVICE_DOZING = 1 << 21; + public static final long SYSUI_STATE_DEVICE_DOZING = 1L << 21; // The home feature is disabled (either by SUW/SysUI/device policy) - public static final int SYSUI_STATE_BACK_DISABLED = 1 << 22; + public static final long SYSUI_STATE_BACK_DISABLED = 1L << 22; // The bubble stack is expanded AND the mange menu for bubbles is expanded on top of it. - public static final int SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED = 1 << 23; + public static final long SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED = 1L << 23; // The voice interaction session window is showing - public static final int SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING = 1 << 25; + public static final long SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING = 1L << 25; // Freeform windows are showing in desktop mode - public static final int SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1 << 26; + public static final long SYSUI_STATE_FREEFORM_ACTIVE_IN_DESKTOP_MODE = 1L << 26; // Device dreaming state - public static final int SYSUI_STATE_DEVICE_DREAMING = 1 << 27; + public static final long SYSUI_STATE_DEVICE_DREAMING = 1L << 27; // Whether the device is currently awake (as opposed to asleep, see WakefulnessLifecycle). // Note that the device is awake on while waking up on, but not while going to sleep. - public static final int SYSUI_STATE_AWAKE = 1 << 28; + public static final long SYSUI_STATE_AWAKE = 1L << 28; // Whether the device is currently transitioning between awake/asleep indicated by // SYSUI_STATE_AWAKE. - public static final int SYSUI_STATE_WAKEFULNESS_TRANSITION = 1 << 29; + public static final long SYSUI_STATE_WAKEFULNESS_TRANSITION = 1L << 29; // The notification panel expansion fraction is > 0 - public static final int SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE = 1 << 30; + public static final long SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE = 1L << 30; // When keyguard will be dismissed but didn't start animation yet - public static final int SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY = 1 << 31; + public static final long SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY = 1L << 31; + // Physical keyboard shortcuts helper is showing + public static final long SYSUI_STATE_SHORTCUT_HELPER_SHOWING = 1L << 32; // Mask for SystemUiStateFlags to isolate SYSUI_STATE_AWAKE and // SYSUI_STATE_WAKEFULNESS_TRANSITION, to match WAKEFULNESS_* constants - public static final int SYSUI_STATE_WAKEFULNESS_MASK = + public static final long SYSUI_STATE_WAKEFULNESS_MASK = SYSUI_STATE_AWAKE | SYSUI_STATE_WAKEFULNESS_TRANSITION; // Mirroring the WakefulnessLifecycle#Wakefulness states - public static final int WAKEFULNESS_ASLEEP = 0; - public static final int WAKEFULNESS_AWAKE = SYSUI_STATE_AWAKE; - public static final int WAKEFULNESS_GOING_TO_SLEEP = SYSUI_STATE_WAKEFULNESS_TRANSITION; - public static final int WAKEFULNESS_WAKING = + public static final long WAKEFULNESS_ASLEEP = 0; + public static final long WAKEFULNESS_AWAKE = SYSUI_STATE_AWAKE; + public static final long WAKEFULNESS_GOING_TO_SLEEP = SYSUI_STATE_WAKEFULNESS_TRANSITION; + public static final long WAKEFULNESS_WAKING = SYSUI_STATE_WAKEFULNESS_TRANSITION | SYSUI_STATE_AWAKE; // Whether the back gesture is allowed (or ignored) by the Shade public static final boolean ALLOW_BACK_GESTURE_IN_SHADE = shadeAllowBackGesture(); @Retention(RetentionPolicy.SOURCE) - @IntDef({SYSUI_STATE_SCREEN_PINNING, + @LongDef({SYSUI_STATE_SCREEN_PINNING, SYSUI_STATE_NAV_BAR_HIDDEN, SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED, SYSUI_STATE_QUICK_SETTINGS_EXPANDED, @@ -167,10 +169,11 @@ public class QuickStepContract { SYSUI_STATE_WAKEFULNESS_TRANSITION, SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE, SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY, + SYSUI_STATE_SHORTCUT_HELPER_SHOWING, }) public @interface SystemUiStateFlags {} - public static String getSystemUiStateString(int flags) { + public static String getSystemUiStateString(long flags) { StringJoiner str = new StringJoiner("|"); if ((flags & SYSUI_STATE_SCREEN_PINNING) != 0) { str.add("screen_pinned"); @@ -265,6 +268,9 @@ public class QuickStepContract { if ((flags & SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY) != 0) { str.add("keygrd_going_away"); } + if ((flags & SYSUI_STATE_SHORTCUT_HELPER_SHOWING) != 0) { + str.add("shortcut_helper_showing"); + } return str.toString(); } @@ -285,13 +291,13 @@ public class QuickStepContract { * Returns whether the specified sysui state is such that the assistant gesture should be * disabled. */ - public static boolean isAssistantGestureDisabled(int sysuiStateFlags) { + public static boolean isAssistantGestureDisabled(long sysuiStateFlags) { if ((sysuiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0) { sysuiStateFlags &= ~SYSUI_STATE_NAV_BAR_HIDDEN; } // Disable when in quick settings, screen pinning, immersive, the bouncer is showing, // or search is disabled - int disableFlags = SYSUI_STATE_SCREEN_PINNING + long disableFlags = SYSUI_STATE_SCREEN_PINNING | SYSUI_STATE_NAV_BAR_HIDDEN | SYSUI_STATE_BOUNCER_SHOWING | SYSUI_STATE_SEARCH_DISABLED @@ -313,7 +319,7 @@ public class QuickStepContract { * Returns whether the specified sysui state is such that the back gesture should be * disabled. */ - public static boolean isBackGestureDisabled(int sysuiStateFlags, boolean forTrackpad) { + public static boolean isBackGestureDisabled(long sysuiStateFlags, boolean forTrackpad) { // Always allow when the bouncer/global actions/voice session is showing (even on top of // the keyguard) if ((sysuiStateFlags & SYSUI_STATE_BOUNCER_SHOWING) != 0 @@ -328,9 +334,9 @@ public class QuickStepContract { return (sysuiStateFlags & getBackGestureDisabledMask(forTrackpad)) != 0; } - private static int getBackGestureDisabledMask(boolean forTrackpad) { + private static long getBackGestureDisabledMask(boolean forTrackpad) { // Disable when in immersive, or the notifications are interactive - int disableFlags = SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; + long disableFlags = SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING; if (!forTrackpad) { disableFlags |= SYSUI_STATE_NAV_BAR_HIDDEN; } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 9ba41ef9ff47..298c0f782b79 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -73,7 +73,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.jank.InteractionJankMonitor; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.biometrics.AuthController.ScaleFactorProvider; -import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor; import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor; import com.android.systemui.biometrics.shared.model.BiometricModalities; import com.android.systemui.biometrics.shared.model.PromptKind; @@ -150,7 +149,6 @@ public class AuthContainerView extends LinearLayout private final CoroutineScope mApplicationCoroutineScope; // TODO(b/287311775): these should be migrated out once ready - private final Provider<PromptCredentialInteractor> mPromptCredentialInteractor; private final @NonNull Provider<PromptSelectorInteractor> mPromptSelectorInteractorProvider; // TODO(b/287311775): these should be migrated out of the view private final Provider<CredentialViewModel> mCredentialViewModelProvider; @@ -311,7 +309,6 @@ public class AuthContainerView extends LinearLayout @NonNull UserManager userManager, @NonNull LockPatternUtils lockPatternUtils, @NonNull InteractionJankMonitor jankMonitor, - @NonNull Provider<PromptCredentialInteractor> promptCredentialInteractor, @NonNull Provider<PromptSelectorInteractor> promptSelectorInteractor, @NonNull PromptViewModel promptViewModel, @NonNull Provider<CredentialViewModel> credentialViewModelProvider, @@ -319,7 +316,7 @@ public class AuthContainerView extends LinearLayout @NonNull VibratorHelper vibratorHelper) { this(config, applicationCoroutineScope, fpProps, faceProps, wakefulnessLifecycle, panelInteractionDetector, userManager, lockPatternUtils, - jankMonitor, promptSelectorInteractor, promptCredentialInteractor, promptViewModel, + jankMonitor, promptSelectorInteractor, promptViewModel, credentialViewModelProvider, new Handler(Looper.getMainLooper()), bgExecutor, vibratorHelper); } @@ -335,7 +332,6 @@ public class AuthContainerView extends LinearLayout @NonNull LockPatternUtils lockPatternUtils, @NonNull InteractionJankMonitor jankMonitor, @NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider, - @NonNull Provider<PromptCredentialInteractor> credentialInteractor, @NonNull PromptViewModel promptViewModel, @NonNull Provider<CredentialViewModel> credentialViewModelProvider, @NonNull Handler mainHandler, @@ -358,13 +354,19 @@ public class AuthContainerView extends LinearLayout mLinearOutSlowIn = Interpolators.LINEAR_OUT_SLOW_IN; mBiometricCallback = new BiometricCallback(); + mFpProps = fpProps; + mFaceProps = faceProps; + final BiometricModalities biometricModalities = new BiometricModalities( + Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds), + Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds)); + mPromptSelectorInteractorProvider = promptSelectorInteractorProvider; - mPromptSelectorInteractorProvider.get().setShouldShowBpWithoutIconForCredential( - config.mPromptInfo); + mPromptSelectorInteractorProvider.get().setPrompt(mConfig.mPromptInfo, mEffectiveUserId, + biometricModalities, mConfig.mOperationId, mConfig.mOpPackageName, + false /*onSwitchToCredential*/); final LayoutInflater layoutInflater = LayoutInflater.from(mContext); - if (constraintBp() && (Utils.isBiometricAllowed(config.mPromptInfo) - || mPromptViewModel.getShowBpWithoutIconForCredential().getValue())) { + if (constraintBp() && mPromptViewModel.getPromptKind().getValue().isBiometric()) { mLayout = (ConstraintLayout) layoutInflater.inflate( R.layout.biometric_prompt_constraint_layout, this, false /* attachToRoot */); } else { @@ -398,10 +400,7 @@ public class AuthContainerView extends LinearLayout mPanelController = new AuthPanelController(mContext, mPanelView); mBackgroundExecutor = bgExecutor; mInteractionJankMonitor = jankMonitor; - mPromptCredentialInteractor = credentialInteractor; mCredentialViewModelProvider = credentialViewModelProvider; - mFpProps = fpProps; - mFaceProps = faceProps; showPrompt(config, layoutInflater, promptViewModel, Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds), @@ -430,11 +429,12 @@ public class AuthContainerView extends LinearLayout @Nullable FaceSensorPropertiesInternal faceProps, @NonNull VibratorHelper vibratorHelper ) { - if (Utils.isBiometricAllowed(config.mPromptInfo) - || mPromptViewModel.getShowBpWithoutIconForCredential().getValue()) { + if (mPromptViewModel.getPromptKind().getValue().isBiometric()) { addBiometricView(config, layoutInflater, viewModel, fpProps, faceProps, vibratorHelper); - } else if (constraintBp() && Utils.isDeviceCredentialAllowed(mConfig.mPromptInfo)) { - addCredentialView(true, false); + } else if (mPromptViewModel.getPromptKind().getValue().isCredential()) { + if (constraintBp()) { + addCredentialView(true, false); + } } else { mPromptSelectorInteractorProvider.get().resetPrompt(); } @@ -445,12 +445,6 @@ public class AuthContainerView extends LinearLayout @Nullable FingerprintSensorPropertiesInternal fpProps, @Nullable FaceSensorPropertiesInternal faceProps, @NonNull VibratorHelper vibratorHelper) { - mPromptSelectorInteractorProvider.get().useBiometricsForAuthentication( - config.mPromptInfo, - config.mUserId, - config.mOperationId, - new BiometricModalities(fpProps, faceProps), - config.mOpPackageName); if (constraintBp()) { mBiometricView = BiometricViewBinder.bind(mLayout, viewModel, null, @@ -519,10 +513,6 @@ public class AuthContainerView extends LinearLayout // disable it. mBackgroundView.setOnClickListener(null); mBackgroundView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); - - mPromptSelectorInteractorProvider.get().useCredentialsForAuthentication( - mConfig.mPromptInfo, credentialType, mConfig.mUserId, mConfig.mOperationId, - mConfig.mOpPackageName); final CredentialViewModel vm = mCredentialViewModelProvider.get(); vm.setAnimateContents(animateContents); ((CredentialView) mCredentialView).init(vm, this, mPanelController, animatePanel, @@ -557,10 +547,9 @@ public class AuthContainerView extends LinearLayout () -> animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED)); if (constraintBp()) { // Do nothing on attachment with constraintLayout - } else if (Utils.isBiometricAllowed(mConfig.mPromptInfo) - || mPromptViewModel.getShowBpWithoutIconForCredential().getValue()) { + } else if (mPromptViewModel.getPromptKind().getValue().isBiometric()) { mBiometricScrollView.addView(mBiometricView.asView()); - } else if (Utils.isDeviceCredentialAllowed(mConfig.mPromptInfo)) { + } else if (mPromptViewModel.getPromptKind().getValue().isCredential()) { addCredentialView(true /* animatePanel */, false /* animateContents */); } else { throw new IllegalStateException("Unknown configuration: " diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java index ca88d40df6af..d6d40f28d288 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java @@ -69,7 +69,6 @@ import com.android.internal.os.SomeArgs; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.CoreStartable; import com.android.systemui.biometrics.domain.interactor.LogContextInteractor; -import com.android.systemui.biometrics.domain.interactor.PromptCredentialInteractor; import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor; import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams; import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel; @@ -139,7 +138,6 @@ public class AuthController implements private Job mBiometricContextListenerJob = null; // TODO: these should be migrated out once ready - @NonNull private final Provider<PromptCredentialInteractor> mPromptCredentialInteractor; @NonNull private final Provider<PromptSelectorInteractor> mPromptSelectorInteractor; @NonNull private final Provider<CredentialViewModel> mCredentialViewModelProvider; @NonNull private final Provider<PromptViewModel> mPromptViewModelProvider; @@ -735,7 +733,6 @@ public class AuthController implements @NonNull LockPatternUtils lockPatternUtils, @NonNull Lazy<UdfpsLogger> udfpsLogger, @NonNull Lazy<LogContextInteractor> logContextInteractor, - @NonNull Provider<PromptCredentialInteractor> promptCredentialInteractorProvider, @NonNull Provider<PromptSelectorInteractor> promptSelectorInteractorProvider, @NonNull Provider<CredentialViewModel> credentialViewModelProvider, @NonNull Provider<PromptViewModel> promptViewModelProvider, @@ -768,7 +765,6 @@ public class AuthController implements mLogContextInteractor = logContextInteractor; mPromptSelectorInteractor = promptSelectorInteractorProvider; - mPromptCredentialInteractor = promptCredentialInteractorProvider; mPromptViewModelProvider = promptViewModelProvider; mCredentialViewModelProvider = credentialViewModelProvider; @@ -1253,6 +1249,8 @@ public class AuthController implements } mCurrentDialog = newDialog; + // TODO(b/339532378): We should check whether |allowBackgroundAuthentication| should be + // removed. if (!promptInfo.isAllowBackgroundAuthentication() && !isOwnerInForeground()) { cancelIfOwnerIsNotInForeground(); } else { @@ -1316,8 +1314,8 @@ public class AuthController implements config.mScaleProvider = this::getScaleFactor; return new AuthContainerView(config, mApplicationCoroutineScope, mFpProps, mFaceProps, wakefulnessLifecycle, panelInteractionDetector, userManager, lockPatternUtils, - mInteractionJankMonitor, mPromptCredentialInteractor, mPromptSelectorInteractor, - viewModel, mCredentialViewModelProvider, bgExecutor, mVibratorHelper); + mInteractionJankMonitor, mPromptSelectorInteractor, viewModel, + mCredentialViewModelProvider, bgExecutor, mVibratorHelper); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt index 20e81c293e40..14d8caf2a5b7 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/BiometricsModule.kt @@ -16,8 +16,10 @@ package com.android.systemui.biometrics.dagger +import android.content.Context import android.content.res.Resources import com.android.internal.R +import com.android.launcher3.icons.IconProvider import com.android.systemui.CoreStartable import com.android.systemui.biometrics.AuthController import com.android.systemui.biometrics.EllipseOverlapDetectorParams @@ -111,6 +113,9 @@ interface BiometricsModule { @Provides fun providesUdfpsUtils(): UdfpsUtils = UdfpsUtils() @Provides + fun provideIconProvider(context: Context): IconProvider = IconProvider(context) + + @Provides @SysUISingleton fun providesOverlapDetector(): OverlapDetector { val selectedOption = diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt index f659ff0a4749..58b238b820c3 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/data/repository/PromptRepository.kt @@ -16,12 +16,8 @@ package com.android.systemui.biometrics.data.repository -import android.hardware.biometrics.Flags import android.hardware.biometrics.PromptInfo -import com.android.systemui.Flags.constraintBp import com.android.systemui.biometrics.AuthController -import com.android.systemui.biometrics.Utils -import com.android.systemui.biometrics.Utils.isDeviceCredentialAllowed import com.android.systemui.biometrics.shared.model.PromptKind import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow @@ -56,8 +52,8 @@ interface PromptRepository { /** The gatekeeper challenge, if one is associated with this prompt. */ val challenge: StateFlow<Long?> - /** The kind of credential to use (biometric, pin, pattern, etc.). */ - val kind: StateFlow<PromptKind> + /** The kind of prompt to use (biometric, pin, pattern, etc.). */ + val promptKind: StateFlow<PromptKind> /** The package name that the prompt is called from. */ val opPackageName: StateFlow<String?> @@ -69,18 +65,6 @@ interface PromptRepository { */ val isConfirmationRequired: Flow<Boolean> - /** - * If biometric prompt without icon needs to show for displaying content prior to credential - * view. - */ - val showBpWithoutIconForCredential: StateFlow<Boolean> - - /** - * Update whether biometric prompt without icon needs to show for displaying content prior to - * credential view, which should be set before [setPrompt]. - */ - fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo) - /** Update the prompt configuration, which should be set before [isShowing]. */ fun setPrompt( promptInfo: PromptInfo, @@ -125,8 +109,8 @@ constructor( private val _userId: MutableStateFlow<Int?> = MutableStateFlow(null) override val userId = _userId.asStateFlow() - private val _kind: MutableStateFlow<PromptKind> = MutableStateFlow(PromptKind.None) - override val kind = _kind.asStateFlow() + private val _promptKind: MutableStateFlow<PromptKind> = MutableStateFlow(PromptKind.None) + override val promptKind = _promptKind.asStateFlow() private val _opPackageName: MutableStateFlow<String?> = MutableStateFlow(null) override val opPackageName = _opPackageName.asStateFlow() @@ -145,21 +129,6 @@ constructor( } .distinctUntilChanged() - private val _showBpWithoutIconForCredential: MutableStateFlow<Boolean> = MutableStateFlow(false) - override val showBpWithoutIconForCredential = _showBpWithoutIconForCredential.asStateFlow() - - override fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo) { - val hasCredentialViewShown = kind.value.isCredential() - val showBpForCredential = - Flags.customBiometricPrompt() && - constraintBp() && - !Utils.isBiometricAllowed(promptInfo) && - isDeviceCredentialAllowed(promptInfo) && - promptInfo.contentView != null && - !promptInfo.isContentViewMoreOptionsButtonUsed - _showBpWithoutIconForCredential.value = showBpForCredential && !hasCredentialViewShown - } - override fun setPrompt( promptInfo: PromptInfo, userId: Int, @@ -167,7 +136,7 @@ constructor( kind: PromptKind, opPackageName: String, ) { - _kind.value = kind + _promptKind.value = kind _userId.value = userId _challenge.value = gatekeeperChallenge _promptInfo.value = promptInfo @@ -178,7 +147,7 @@ constructor( _promptInfo.value = null _userId.value = null _challenge.value = null - _kind.value = PromptKind.None + _promptKind.value = PromptKind.None _opPackageName.value = null } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt index f8fb7bb7dff7..14ba8a22a65e 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptCredentialInteractor.kt @@ -66,13 +66,13 @@ constructor( biometricPromptRepository.promptInfo, biometricPromptRepository.challenge, biometricPromptRepository.userId, - biometricPromptRepository.kind - ) { promptInfo, challenge, userId, kind -> + biometricPromptRepository.promptKind + ) { promptInfo, challenge, userId, promptKind -> if (promptInfo == null || userId == null || challenge == null) { return@combine null } - when (kind) { + when (promptKind) { PromptKind.Pin -> BiometricPromptRequest.Credential.Pin( info = promptInfo, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt index deb47d309ea5..4ba780fcec69 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractor.kt @@ -16,8 +16,10 @@ package com.android.systemui.biometrics.domain.interactor +import android.hardware.biometrics.Flags import android.hardware.biometrics.PromptInfo import com.android.internal.widget.LockPatternUtils +import com.android.systemui.biometrics.Utils import com.android.systemui.biometrics.Utils.getCredentialType import com.android.systemui.biometrics.Utils.isDeviceCredentialAllowed import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository @@ -52,12 +54,16 @@ interface PromptSelectorInteractor { /** Static metadata about the current prompt. */ val prompt: Flow<BiometricPromptRequest.Biometric?> + /** The kind of prompt to use (biometric, pin, pattern, etc.). */ + val promptKind: StateFlow<PromptKind> + /** If using a credential is allowed. */ val isCredentialAllowed: Flow<Boolean> /** - * The kind of credential the user may use as a fallback or [PromptKind.Biometric] if unknown or - * not [isCredentialAllowed]. + * The kind of credential the user may use as a fallback or [PromptKind.None] if unknown or not + * [isCredentialAllowed]. This is separate from [promptKind], even if [promptKind] is + * [PromptKind.Biometric], [credentialKind] should still be one of pin/pattern/password. */ val credentialKind: Flow<PromptKind> @@ -70,34 +76,20 @@ interface PromptSelectorInteractor { /** Fingerprint sensor type */ val sensorType: Flow<FingerprintSensorType> - /** - * If biometric prompt without icon needs to show for displaying content prior to credential - * view. - */ - val showBpWithoutIconForCredential: StateFlow<Boolean> + /** Switch to the credential view. */ + fun onSwitchToCredential() /** - * Update whether biometric prompt without icon needs to show for displaying content prior to - * credential view, which should be set before [PromptRepository.setPrompt]. + * Update the kind of prompt (biometric prompt w/ or w/o sensor icon, pin view, pattern view, + * etc). */ - fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo) - - /** Use biometrics for authentication. */ - fun useBiometricsForAuthentication( + fun setPrompt( promptInfo: PromptInfo, - userId: Int, - challenge: Long, + effectiveUserId: Int, modalities: BiometricModalities, - opPackageName: String, - ) - - /** Use credential-based authentication instead of biometrics. */ - fun useCredentialsForAuthentication( - promptInfo: PromptInfo, - kind: PromptKind, - userId: Int, challenge: Long, opPackageName: String, + onSwitchToCredential: Boolean, ) /** Unset the current authentication request. */ @@ -110,7 +102,7 @@ class PromptSelectorInteractorImpl constructor( fingerprintPropertyRepository: FingerprintPropertyRepository, private val promptRepository: PromptRepository, - lockPatternUtils: LockPatternUtils, + private val lockPatternUtils: LockPatternUtils, ) : PromptSelectorInteractor { override val prompt: Flow<BiometricPromptRequest.Biometric?> = @@ -118,7 +110,7 @@ constructor( promptRepository.promptInfo, promptRepository.challenge, promptRepository.userId, - promptRepository.kind, + promptRepository.promptKind, promptRepository.opPackageName, ) { promptInfo, challenge, userId, kind, opPackageName -> if ( @@ -140,6 +132,8 @@ constructor( } } + override val promptKind: StateFlow<PromptKind> = promptRepository.promptKind + override val isConfirmationRequired: Flow<Boolean> = promptRepository.isConfirmationRequired.distinctUntilChanged() @@ -153,44 +147,57 @@ constructor( if (prompt != null && isAllowed) { getCredentialType(lockPatternUtils, prompt.userInfo.deviceCredentialOwnerId) } else { - PromptKind.Biometric() + PromptKind.None } } override val sensorType: Flow<FingerprintSensorType> = fingerprintPropertyRepository.sensorType - override val showBpWithoutIconForCredential = promptRepository.showBpWithoutIconForCredential - - override fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo) { - promptRepository.setShouldShowBpWithoutIconForCredential(promptInfo) - } - - override fun useBiometricsForAuthentication( - promptInfo: PromptInfo, - userId: Int, - challenge: Long, - modalities: BiometricModalities, - opPackageName: String, - ) { - promptRepository.setPrompt( - promptInfo = promptInfo, - userId = userId, - gatekeeperChallenge = challenge, - kind = PromptKind.Biometric(modalities), - opPackageName = opPackageName, + override fun onSwitchToCredential() { + val modalities: BiometricModalities = + if (promptRepository.promptKind.value.isBiometric()) + (promptRepository.promptKind.value as PromptKind.Biometric).activeModalities + else BiometricModalities() + setPrompt( + promptRepository.promptInfo.value!!, + promptRepository.userId.value!!, + modalities, + promptRepository.challenge.value!!, + promptRepository.opPackageName.value!!, + true /*onSwitchToCredential*/ ) } - override fun useCredentialsForAuthentication( + override fun setPrompt( promptInfo: PromptInfo, - kind: PromptKind, - userId: Int, + effectiveUserId: Int, + modalities: BiometricModalities, challenge: Long, opPackageName: String, + onSwitchToCredential: Boolean, ) { + val hasCredentialViewShown = promptKind.value.isCredential() + val showBpForCredential = + Flags.customBiometricPrompt() && + com.android.systemui.Flags.constraintBp() && + !Utils.isBiometricAllowed(promptInfo) && + isDeviceCredentialAllowed(promptInfo) && + promptInfo.contentView != null && + !promptInfo.isContentViewMoreOptionsButtonUsed + val showBpWithoutIconForCredential = showBpForCredential && !hasCredentialViewShown + var kind: PromptKind = PromptKind.None + if (onSwitchToCredential) { + kind = getCredentialType(lockPatternUtils, effectiveUserId) + } else if (Utils.isBiometricAllowed(promptInfo) || showBpWithoutIconForCredential) { + // TODO(b/330908557): check to show one pane or two pane + kind = PromptKind.Biometric(modalities) + } else if (isDeviceCredentialAllowed(promptInfo)) { + kind = getCredentialType(lockPatternUtils, effectiveUserId) + } + promptRepository.setPrompt( promptInfo = promptInfo, - userId = userId, + userId = effectiveUserId, gatekeeperChallenge = challenge, kind = kind, opPackageName = opPackageName, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt index 6f079e2d3b3a..4f96c1e03d11 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/model/BiometricPromptRequest.kt @@ -1,5 +1,6 @@ package com.android.systemui.biometrics.domain.model +import android.content.ComponentName import android.graphics.Bitmap import android.hardware.biometrics.PromptContentView import android.hardware.biometrics.PromptInfo @@ -43,6 +44,9 @@ sealed class BiometricPromptRequest( val logoBitmap: Bitmap? = info.logoBitmap val logoDescription: String? = info.logoDescription val negativeButtonText: String = info.negativeButtonText?.toString() ?: "" + val componentNameForConfirmDeviceCredentialActivity: ComponentName? = + info.componentNameForConfirmDeviceCredentialActivity + val allowBackgroundAuthentication = info.isAllowBackgroundAuthentication } /** Prompt using a credential (pin, pattern, password). */ diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt index da5695163cb4..65c5b6b3859c 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt @@ -230,7 +230,7 @@ object BiometricViewBinder { } lifecycleScope.launch { - viewModel.showBpWithoutIconForCredential.collect { showWithoutIcon -> + viewModel.hideSensorIcon.collect { showWithoutIcon -> if (!showWithoutIcon) { PromptIconViewBinder.bind( iconView, diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt index d1ad783c7cc8..f0969eda4029 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt @@ -55,6 +55,7 @@ import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.res.R import kotlin.math.abs import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch /** Helper for [BiometricViewBinder] to handle resize transitions. */ @@ -169,14 +170,14 @@ object BiometricViewSizeBinder { val flipConstraintSet = ConstraintSet() view.doOnLayout { - fun setVisibilities(size: PromptSize) { + fun setVisibilities(hideSensorIcon: Boolean, size: PromptSize) { viewsToHideWhenSmall.forEach { it.showContentOrHide(forceHide = size.isSmall) } largeConstraintSet.setVisibility(iconHolderView.id, View.GONE) largeConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE) largeConstraintSet.setVisibility(R.id.indicator, View.GONE) largeConstraintSet.setVisibility(R.id.scrollView, View.GONE) - if (viewModel.showBpWithoutIconForCredential.value) { + if (hideSensorIcon) { smallConstraintSet.setVisibility(iconHolderView.id, View.GONE) smallConstraintSet.setVisibility(R.id.biometric_icon_overlay, View.GONE) smallConstraintSet.setVisibility(R.id.indicator, View.GONE) @@ -362,12 +363,16 @@ object BiometricViewSizeBinder { } } } + lifecycleScope.launch { + combine(viewModel.hideSensorIcon, viewModel.size, ::Pair).collect { + (hideSensorIcon, size) -> + setVisibilities(hideSensorIcon, size) + } + } lifecycleScope.launch { combine(viewModel.position, viewModel.size, ::Pair).collect { (position, size) -> - setVisibilities(size) - if (position.isLeft) { if (size.isSmall) { flipConstraintSet.clone(smallConstraintSet) @@ -481,7 +486,7 @@ object BiometricViewSizeBinder { v.showContentOrHide(forceHide = size.isSmall) } - if (viewModel.showBpWithoutIconForCredential.value) { + if (viewModel.hideSensorIcon.first()) { iconHolderView.visibility = View.GONE } @@ -492,10 +497,6 @@ object BiometricViewSizeBinder { viewsToFadeInOnSizeChange.forEach { it.alpha = 0f } } - // TODO(b/302735104): Fix wrong height due to the delay of - // PromptContentView. addOnLayoutChangeListener() will cause crash - // when showing credential view, since |PromptIconViewModel| won't - // release the flow. // propagate size changes to legacy panel controller and animate // transitions view.doOnLayout { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt index 2104f3e1fba6..156ec6b975a5 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt @@ -16,7 +16,10 @@ package com.android.systemui.biometrics.ui.viewmodel +import android.app.ActivityTaskManager +import android.content.ComponentName import android.content.Context +import android.content.pm.ActivityInfo import android.content.pm.ApplicationInfo import android.content.pm.PackageManager import android.graphics.Rect @@ -26,18 +29,22 @@ import android.hardware.biometrics.BiometricFingerprintConstants import android.hardware.biometrics.BiometricPrompt import android.hardware.biometrics.Flags.customBiometricPrompt import android.hardware.biometrics.PromptContentView +import android.os.UserHandle import android.util.Log import android.util.RotationUtils import android.view.HapticFeedbackConstants import android.view.MotionEvent +import com.android.launcher3.icons.IconProvider import com.android.systemui.Flags.bpTalkback import com.android.systemui.Flags.constraintBp import com.android.systemui.biometrics.UdfpsUtils import com.android.systemui.biometrics.Utils +import com.android.systemui.biometrics.Utils.isSystem import com.android.systemui.biometrics.domain.interactor.BiometricStatusInteractor import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor +import com.android.systemui.biometrics.domain.model.BiometricPromptRequest import com.android.systemui.biometrics.shared.model.BiometricModalities import com.android.systemui.biometrics.shared.model.BiometricModality import com.android.systemui.biometrics.shared.model.DisplayRotation @@ -67,11 +74,13 @@ class PromptViewModel @Inject constructor( displayStateInteractor: DisplayStateInteractor, - promptSelectorInteractor: PromptSelectorInteractor, + private val promptSelectorInteractor: PromptSelectorInteractor, @Application private val context: Context, private val udfpsOverlayInteractor: UdfpsOverlayInteractor, private val biometricStatusInteractor: BiometricStatusInteractor, - private val udfpsUtils: UdfpsUtils + private val udfpsUtils: UdfpsUtils, + private val iconProvider: IconProvider, + private val activityTaskManager: ActivityTaskManager, ) { /** The set of modalities available for this prompt */ val modalities: Flow<BiometricModalities> = @@ -195,8 +204,11 @@ constructor( /** The kind of credential the user has. */ val credentialKind: Flow<PromptKind> = promptSelectorInteractor.credentialKind - val showBpWithoutIconForCredential: StateFlow<Boolean> = - promptSelectorInteractor.showBpWithoutIconForCredential + /** The kind of prompt to use (biometric, pin, pattern, etc.). */ + val promptKind: StateFlow<PromptKind> = promptSelectorInteractor.promptKind + + /** Whether the sensor icon on biometric prompt ui should be hidden. */ + val hideSensorIcon: Flow<Boolean> = modalities.map { it.isEmpty }.distinctUntilChanged() /** The label to use for the cancel button. */ val negativeButtonText: Flow<String> = @@ -496,14 +508,7 @@ constructor( !(customBiometricPrompt() && constraintBp()) || it == null -> null it.logoRes != -1 -> context.resources.getDrawable(it.logoRes, context.theme) it.logoBitmap != null -> BitmapDrawable(context.resources, it.logoBitmap) - else -> - try { - val info = context.getApplicationInfo(it.opPackageName) - context.packageManager.getApplicationIcon(info) - } catch (e: Exception) { - Log.w(TAG, "Cannot find icon for package " + it.opPackageName, e) - null - } + else -> context.getUserBadgedIcon(it, iconProvider, activityTaskManager) } } .distinctUntilChanged() @@ -514,15 +519,8 @@ constructor( .map { when { !(customBiometricPrompt() && constraintBp()) || it == null -> "" - it.logoDescription != null -> it.logoDescription - else -> - try { - val info = context.getApplicationInfo(it.opPackageName) - context.packageManager.getApplicationLabel(info).toString() - } catch (e: Exception) { - Log.w(TAG, "Cannot find name for package " + it.opPackageName, e) - "" - } + !it.logoDescription.isNullOrEmpty() -> it.logoDescription + else -> context.getUserBadgedLabel(it, activityTaskManager) } } .distinctUntilChanged() @@ -896,6 +894,7 @@ constructor( */ fun onSwitchToCredential() { _forceLargeSize.value = true + promptSelectorInteractor.onSwitchToCredential() } private fun vibrateOnSuccess() { @@ -922,15 +921,109 @@ constructor( } companion object { - private const val TAG = "PromptViewModel" + const val TAG = "PromptViewModel" } } -private fun Context.getApplicationInfo(packageName: String): ApplicationInfo = - packageManager.getApplicationInfo( - packageName, - PackageManager.MATCH_DISABLED_COMPONENTS or PackageManager.MATCH_ANY_USER - ) +private fun Context.getUserBadgedIcon( + prompt: BiometricPromptRequest.Biometric, + iconProvider: IconProvider, + activityTaskManager: ActivityTaskManager +): Drawable? { + var icon: Drawable? = null + val componentName = prompt.getComponentNameForLogo(activityTaskManager) + if (componentName != null && shouldShowLogoWithOverrides(componentName)) { + val activityInfo = getActivityInfo(componentName) + icon = if (activityInfo == null) null else iconProvider.getIcon(activityInfo) + } + if (icon == null) { + val appInfo = prompt.getApplicationInfoForLogo(this, componentName) + if (appInfo == null) { + Log.w(PromptViewModel.TAG, "Cannot find app logo for package $opPackageName") + return null + } else { + icon = packageManager.getApplicationIcon(appInfo) + } + } + return packageManager.getUserBadgedIcon(icon, UserHandle.of(prompt.userInfo.userId)) +} + +private fun Context.getUserBadgedLabel( + prompt: BiometricPromptRequest.Biometric, + activityTaskManager: ActivityTaskManager +): String { + val componentName = prompt.getComponentNameForLogo(activityTaskManager) + val appInfo = prompt.getApplicationInfoForLogo(this, componentName) + return if (appInfo == null || packageManager.getApplicationLabel(appInfo).isNullOrEmpty()) { + Log.w(PromptViewModel.TAG, "Cannot find app logo for package $opPackageName") + "" + } else { + packageManager + .getUserBadgedLabel(packageManager.getApplicationLabel(appInfo), UserHandle.of(userId)) + .toString() + } +} + +private fun BiometricPromptRequest.Biometric.getComponentNameForLogo( + activityTaskManager: ActivityTaskManager +): ComponentName? { + val topActivity: ComponentName? = activityTaskManager.getTasks(1).firstOrNull()?.topActivity + return when { + componentNameForConfirmDeviceCredentialActivity != null -> + componentNameForConfirmDeviceCredentialActivity + topActivity?.packageName.contentEquals(opPackageName) -> topActivity + else -> { + Log.w(PromptViewModel.TAG, "Top activity $topActivity is not the client $opPackageName") + null + } + } +} + +private fun BiometricPromptRequest.Biometric.getApplicationInfoForLogo( + context: Context, + componentNameForLogo: ComponentName? +): ApplicationInfo? { + val packageName = + when { + componentNameForLogo != null -> componentNameForLogo.packageName + // TODO(b/339532378): We should check whether |allowBackgroundAuthentication| should be + // removed. + // This is being consistent with the check in [AuthController.showDialog()]. + allowBackgroundAuthentication || isSystem(context, opPackageName) -> opPackageName + else -> null + } + return if (packageName == null) { + Log.w(PromptViewModel.TAG, "Cannot find application info for $opPackageName") + null + } else { + context.getApplicationInfo(packageName) + } +} + +private fun Context.shouldShowLogoWithOverrides(componentName: ComponentName): Boolean { + return resources + .getStringArray(R.array.biometric_dialog_package_names_for_logo_with_overrides) + .find { componentName.packageName.contentEquals(it) } != null +} + +private fun Context.getActivityInfo(componentName: ComponentName): ActivityInfo? = + try { + packageManager.getActivityInfo(componentName, 0) + } catch (e: PackageManager.NameNotFoundException) { + Log.w(PromptViewModel.TAG, "Cannot find activity info for $opPackageName", e) + null + } + +private fun Context.getApplicationInfo(packageName: String): ApplicationInfo? = + try { + packageManager.getApplicationInfo( + packageName, + PackageManager.MATCH_DISABLED_COMPONENTS or PackageManager.MATCH_ANY_USER + ) + } catch (e: PackageManager.NameNotFoundException) { + Log.w(PromptViewModel.TAG, "Cannot find application info for $opPackageName", e) + null + } /** How the fingerprint sensor was started for the prompt. */ enum class FingerprintStartMode { diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt index dd8c0df387dc..f0230beaa967 100644 --- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt +++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegate.kt @@ -204,11 +204,7 @@ internal constructor( isEnabled: Boolean, @StringRes infoResId: Int ) { - getAutoOnToggle(dialog).apply { - isChecked = isEnabled - setEnabled(true) - alpha = ENABLED_ALPHA - } + getAutoOnToggle(dialog).isChecked = isEnabled getAutoOnToggleInfoTextView(dialog).text = dialog.context.getString(infoResId) } @@ -236,12 +232,8 @@ internal constructor( } getAutoOnToggleView(dialog).visibility = initialUiProperties.autoOnToggleVisibility - getAutoOnToggle(dialog).setOnCheckedChangeListener { view, isChecked -> + getAutoOnToggle(dialog).setOnCheckedChangeListener { _, isChecked -> mutableBluetoothAutoOnToggle.value = isChecked - view.apply { - isEnabled = false - alpha = DISABLED_ALPHA - } uiEventLogger.log(BluetoothTileDialogUiEvent.BLUETOOTH_AUTO_ON_TOGGLE_CLICKED) } } diff --git a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt index c1be37af3aeb..a51d8ff4faa5 100644 --- a/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt +++ b/packages/SystemUI/src/com/android/systemui/brightness/ui/compose/BrightnessSlider.kt @@ -23,7 +23,6 @@ import androidx.compose.foundation.layout.size import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember @@ -32,6 +31,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.PlatformSlider import com.android.systemui.brightness.shared.GammaBrightness import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel @@ -107,10 +107,13 @@ fun BrightnessSliderContainer( viewModel: BrightnessSliderViewModel, modifier: Modifier = Modifier, ) { - val gamma: Int by viewModel.currentBrightness.map { it.value }.collectAsState(initial = 0) + val gamma: Int by + viewModel.currentBrightness.map { it.value }.collectAsStateWithLifecycle(initialValue = 0) val coroutineScope = rememberCoroutineScope() val restriction by - viewModel.policyRestriction.collectAsState(initial = PolicyRestriction.NoRestriction) + viewModel.policyRestriction.collectAsStateWithLifecycle( + initialValue = PolicyRestriction.NoRestriction + ) BrightnessSlider( gammaValue = gamma, diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java index b42a903878a7..2eca02c2b0d1 100644 --- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingCollectorImpl.java @@ -31,9 +31,12 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.communal.domain.interactor.CommunalInteractor; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor; import com.android.systemui.dock.DockManager; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor; +import com.android.systemui.scene.shared.flag.SceneContainerFlag; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.policy.BatteryController; @@ -88,6 +91,8 @@ class FalsingCollectorImpl implements FalsingCollector { private final JavaAdapter mJavaAdapter; private final SystemClock mSystemClock; private final Lazy<SelectedUserInteractor> mUserInteractor; + private final Lazy<DeviceEntryInteractor> mDeviceEntryInteractor; + private final Lazy<SceneContainerOcclusionInteractor> mSceneContainerOcclusionInteractor; private int mState; private boolean mShowingAod; @@ -170,7 +175,9 @@ class FalsingCollectorImpl implements FalsingCollector { JavaAdapter javaAdapter, SystemClock systemClock, Lazy<SelectedUserInteractor> userInteractor, - Lazy<CommunalInteractor> communalInteractorLazy) { + Lazy<CommunalInteractor> communalInteractorLazy, + Lazy<DeviceEntryInteractor> deviceEntryInteractor, + Lazy<SceneContainerOcclusionInteractor> sceneContainerOcclusionInteractor) { mFalsingDataProvider = falsingDataProvider; mFalsingManager = falsingManager; mKeyguardUpdateMonitor = keyguardUpdateMonitor; @@ -186,6 +193,8 @@ class FalsingCollectorImpl implements FalsingCollector { mSystemClock = systemClock; mUserInteractor = userInteractor; mCommunalInteractorLazy = communalInteractorLazy; + mDeviceEntryInteractor = deviceEntryInteractor; + mSceneContainerOcclusionInteractor = sceneContainerOcclusionInteractor; } @Override @@ -196,7 +205,18 @@ class FalsingCollectorImpl implements FalsingCollector { mStatusBarStateController.addCallback(mStatusBarStateListener); mState = mStatusBarStateController.getState(); - mKeyguardStateController.addCallback(mKeyguardStateControllerCallback); + if (SceneContainerFlag.isEnabled()) { + mJavaAdapter.alwaysCollectFlow( + mDeviceEntryInteractor.get().isDeviceEntered(), + this::isDeviceEnteredChanged + ); + mJavaAdapter.alwaysCollectFlow( + mSceneContainerOcclusionInteractor.get().getInvisibleDueToOcclusion(), + this::isInvisibleDueToOcclusionChanged + ); + } else { + mKeyguardStateController.addCallback(mKeyguardStateControllerCallback); + } mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback); @@ -216,6 +236,14 @@ class FalsingCollectorImpl implements FalsingCollector { mDockManager.addListener(mDockEventListener); } + public void isDeviceEnteredChanged(boolean unused) { + updateSensorRegistration(); + } + + public void isInvisibleDueToOcclusionChanged(boolean unused) { + updateSensorRegistration(); + } + @Override public void onSuccessfulUnlock() { logDebug("REAL: onSuccessfulUnlock"); @@ -302,7 +330,7 @@ class FalsingCollectorImpl implements FalsingCollector { @Override public void onTouchEvent(MotionEvent ev) { logDebug("REAL: onTouchEvent(" + MotionEvent.actionToString(ev.getActionMasked()) + ")"); - if (!mKeyguardStateController.isShowing()) { + if (!isKeyguardShowing()) { avoidGesture(); return; } @@ -399,12 +427,13 @@ class FalsingCollectorImpl implements FalsingCollector { } private boolean shouldBeRegisteredToSensors() { - return mScreenOn - && (mState == StatusBarState.KEYGUARD - || (mState == StatusBarState.SHADE - && mKeyguardStateController.isOccluded() - && mKeyguardStateController.isShowing())) - && !mShowingAod; + final boolean isKeyguard = mState == StatusBarState.KEYGUARD; + + final boolean isShadeOverOccludedKeyguard = mState == StatusBarState.SHADE + && isKeyguardShowing() + && isKeyguardOccluded(); + + return mScreenOn && !mShowingAod && (isKeyguard || isShadeOverOccludedKeyguard); } private void updateSensorRegistration() { @@ -446,6 +475,32 @@ class FalsingCollectorImpl implements FalsingCollector { mFalsingManager.onProximityEvent(new ProximityEventImpl(proximityEvent)); } + /** + * Returns {@code true} if the keyguard is showing (whether or not the screen is on, whether or + * not an activity is occluding the keyguard, and whether or not the shade is open on top of the + * keyguard), or {@code false} if the user has dismissed the keyguard by authenticating or + * swiping up. + */ + private boolean isKeyguardShowing() { + if (SceneContainerFlag.isEnabled()) { + return !mDeviceEntryInteractor.get().isDeviceEntered().getValue(); + } else { + return mKeyguardStateController.isShowing(); + } + } + + /** + * Returns {@code true} if there is an activity display on top of ("occluding") the keyguard, or + * {@code false} if an activity is not occluding the keyguard (including if the keyguard is not + * showing at all). + */ + private boolean isKeyguardOccluded() { + if (SceneContainerFlag.isEnabled()) { + return mSceneContainerOcclusionInteractor.get().getInvisibleDueToOcclusion().getValue(); + } else { + return mKeyguardStateController.isOccluded(); + } + } static void logDebug(String msg) { if (DEBUG) { diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java index 8efc66de24cd..a2afcac87c74 100644 --- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java +++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayView.java @@ -66,11 +66,11 @@ import com.android.systemui.screenshot.ui.binder.ActionButtonViewBinder; import com.android.systemui.screenshot.ui.viewmodel.ActionButtonAppearance; import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel; -import java.util.ArrayList; - import kotlin.Unit; import kotlin.jvm.functions.Function0; +import java.util.ArrayList; + /** * Handles the visual elements and animations for the clipboard overlay. */ @@ -109,6 +109,7 @@ public class ClipboardOverlayView extends DraggableConstraintLayout { private View mDismissButton; private LinearLayout mActionContainer; private ClipboardOverlayCallbacks mClipboardCallbacks; + private ActionButtonViewBinder mActionButtonViewBinder = new ActionButtonViewBinder(); public ClipboardOverlayView(Context context) { this(context, null); @@ -152,7 +153,7 @@ public class ClipboardOverlayView extends DraggableConstraintLayout { private void bindDefaultActionChips() { if (screenshotShelfUi2()) { - ActionButtonViewBinder.INSTANCE.bind(mRemoteCopyChip, + mActionButtonViewBinder.bind(mRemoteCopyChip, ActionButtonViewModel.Companion.withNextId( new ActionButtonAppearance( Icon.createWithResource(mContext, @@ -169,7 +170,7 @@ public class ClipboardOverlayView extends DraggableConstraintLayout { return null; } })); - ActionButtonViewBinder.INSTANCE.bind(mShareChip, + mActionButtonViewBinder.bind(mShareChip, ActionButtonViewModel.Companion.withNextId( new ActionButtonAppearance( Icon.createWithResource(mContext, @@ -512,7 +513,7 @@ public class ClipboardOverlayView extends DraggableConstraintLayout { private View constructShelfActionChip(RemoteAction action, Runnable onFinish) { View chip = LayoutInflater.from(mContext).inflate( R.layout.shelf_action_chip, mActionContainer, false); - ActionButtonViewBinder.INSTANCE.bind(chip, ActionButtonViewModel.Companion.withNextId( + mActionButtonViewBinder.bind(chip, ActionButtonViewModel.Companion.withNextId( new ActionButtonAppearance(action.getIcon().loadDrawable(mContext), action.getTitle(), action.getTitle()), new Function0<>() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt index f437032d0ddb..971ab111d2f6 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalSceneStartable.kt @@ -17,7 +17,6 @@ package com.android.systemui.communal import android.provider.Settings -import android.service.dreams.Flags.dreamTracksFocus import com.android.compose.animation.scene.SceneKey import com.android.systemui.CoreStartable import com.android.systemui.communal.domain.interactor.CommunalInteractor @@ -143,12 +142,10 @@ constructor( } } - if (dreamTracksFocus()) { - bgScope.launch { - communalInteractor.isIdleOnCommunal.collectLatest { - withContext(mainDispatcher) { - notificationShadeWindowController.setGlanceableHubShowing(it) - } + bgScope.launch { + communalInteractor.isIdleOnCommunal.collectLatest { + withContext(mainDispatcher) { + notificationShadeWindowController.setGlanceableHubShowing(it) } } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt index 03f54c8b25d7..5cd15f278f00 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/model/CommunalWidgetCategories.kt @@ -17,15 +17,23 @@ package com.android.systemui.communal.data.model import android.appwidget.AppWidgetProviderInfo +import com.android.settingslib.flags.Flags.allowAllWidgetsOnLockscreenByDefault /** * The widget categories to display on communal hub (where categories is a bitfield with values that * match those in {@link AppWidgetProviderInfo}). */ @JvmInline -value class CommunalWidgetCategories( - // The default is keyguard widgets. - val categories: Int = AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD -) { +value class CommunalWidgetCategories(val categories: Int = defaultCategories) { fun contains(category: Int) = (categories and category) == category + + companion object { + val defaultCategories: Int + get() { + return AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD or + if (allowAllWidgetsOnLockscreenByDefault()) + AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN + else 0 + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt index e2fed6d0ea20..e5a0e5070b94 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalMediaRepository.kt @@ -53,7 +53,7 @@ constructor( updateMediaModel(data) } - override fun onMediaDataRemoved(key: String) { + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { updateMediaModel() } } 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 40d744015498..b27fcfc2f3a7 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 @@ -126,7 +126,7 @@ constructor( private fun observeCtaDismissState(user: UserInfo): Flow<Boolean> = getSharedPrefsForUser(user) - .observe(CTA_DISMISSED_STATE) + .observe() // Emit at the start of collection to ensure we get an initial value .onStart { emit(Unit) } .map { getCtaDismissedState() } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt index 9debe0e56083..88cb64c95c04 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSettingsRepository.kt @@ -18,7 +18,6 @@ package com.android.systemui.communal.data.repository import android.app.admin.DevicePolicyManager import android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_WIDGETS_ALL -import android.appwidget.AppWidgetProviderInfo import android.content.IntentFilter import android.content.pm.UserInfo import android.provider.Settings @@ -108,10 +107,9 @@ constructor( .onStart { emit(Unit) } .map { CommunalWidgetCategories( - // The default is to show only keyguard widgets. secureSettings.getIntForUser( GLANCEABLE_HUB_CONTENT_SETTING, - AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD, + CommunalWidgetCategories.defaultCategories, user.id ) ) diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt index f9de60984e2d..3e5126a307eb 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSettingsInteractor.kt @@ -75,7 +75,7 @@ constructor( scope = bgScope, // Start this eagerly since the value can be accessed synchronously. started = SharingStarted.Eagerly, - initialValue = CommunalWidgetCategories().categories + initialValue = CommunalWidgetCategories.defaultCategories ) private val workProfileUserInfoCallbackFlow: Flow<UserInfo?> = conflatedCallbackFlow { diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt index 1120466c7acc..656e5cbafa97 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt @@ -25,7 +25,6 @@ import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main -import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.log.LogBuffer @@ -67,7 +66,6 @@ constructor( private val communalInteractor: CommunalInteractor, tutorialInteractor: CommunalTutorialInteractor, private val shadeInteractor: ShadeInteractor, - deviceEntryInteractor: DeviceEntryInteractor, @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost, @CommunalLog logBuffer: LogBuffer, ) : BaseCommunalViewModel(communalInteractor, mediaHost) { @@ -142,8 +140,6 @@ constructor( val isEnableWorkProfileDialogShowing: Flow<Boolean> = _isEnableWorkProfileDialogShowing.asStateFlow() - val deviceUnlocked: Flow<Boolean> = deviceEntryInteractor.isUnlocked - init { // Initialize our media host for the UMO. This only needs to happen once and must be done // before the MediaHierarchyManager attempts to move the UMO to the hub. diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt index 7c2dae34707b..060a3318abd0 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/panels/AuthorizedPanelsRepositoryImpl.kt @@ -25,10 +25,10 @@ import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl import com.android.systemui.util.kotlin.SharedPreferencesExt.observe +import com.android.systemui.util.kotlin.emitOnStart import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onStart class AuthorizedPanelsRepositoryImpl @Inject @@ -40,7 +40,7 @@ constructor( override fun observeAuthorizedPanels(user: UserHandle): Flow<Set<String>> { val prefs = instantiateSharedPrefs(user) - return prefs.observe(KEY).onStart { emit(Unit) }.map { getAuthorizedPanelsInternal(prefs) } + return prefs.observe().emitOnStart().map { getAuthorizedPanelsInternal(prefs) } } override fun getAuthorizedPanels(): Set<String> { diff --git a/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt index 9be049400962..691ec76d50ed 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/panels/SelectedComponentRepositoryImpl.kt @@ -26,12 +26,12 @@ import com.android.systemui.settings.UserFileManager import com.android.systemui.settings.UserTracker import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl import com.android.systemui.util.kotlin.SharedPreferencesExt.observe +import com.android.systemui.util.kotlin.emitOnStart import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onStart @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class) @SysUISingleton @@ -63,8 +63,8 @@ constructor( ): Flow<SelectedComponentRepository.SelectedComponent?> { val prefs = getSharedPreferencesForUser(userHandle.identifier) return prefs - .observe(PREF_COMPONENT) - .onStart { emit(Unit) } + .observe() + .emitOnStart() .map { getSelectedComponent(userHandle) } .flowOn(bgDispatcher) } diff --git a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java index 0fd688760a32..8c3de4bd1928 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java +++ b/packages/SystemUI/src/com/android/systemui/doze/dagger/DozeModule.java @@ -89,8 +89,8 @@ public abstract class DozeModule { dozeFalsingManagerAdapter, dozeTriggers, dozeUi, - dozeScreenState, dozeScreenBrightness, + dozeScreenState, dozeWallpaperState, dozeDockHandler, dozeAuthRemover, diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java index 6e043391c197..60006c68639d 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java @@ -16,6 +16,8 @@ package com.android.systemui.dreams; +import static android.service.dreams.Flags.dreamHandlesBeingObscured; + import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress; import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamAlphaScaledExpansion; import static com.android.keyguard.BouncerPanelExpansionCalculator.getDreamYPositionScaledExpansion; @@ -23,8 +25,10 @@ import static com.android.systemui.complication.ComplicationLayoutParams.POSITIO import static com.android.systemui.complication.ComplicationLayoutParams.POSITION_TOP; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; +import static com.android.systemui.util.kotlin.JavaAdapterKt.combineFlows; import android.animation.Animator; +import android.app.DreamManager; import android.content.res.Resources; import android.graphics.Region; import android.os.Handler; @@ -37,7 +41,9 @@ import com.android.dream.lowlight.LowLightTransitionCoordinator; import com.android.systemui.ambient.touch.scrim.BouncerlessScrimController; import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor; import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerCallbackInteractor.PrimaryBouncerExpansionCallback; +import com.android.systemui.communal.domain.interactor.CommunalInteractor; import com.android.systemui.complication.ComplicationHostViewController; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dreams.dagger.DreamOverlayComponent; import com.android.systemui.dreams.dagger.DreamOverlayModule; @@ -45,10 +51,12 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInterac import com.android.systemui.keyguard.shared.model.KeyguardState; import com.android.systemui.res.R; import com.android.systemui.shade.ShadeExpansionChangeEvent; +import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.BlurUtils; import com.android.systemui.util.ViewController; import kotlinx.coroutines.CoroutineDispatcher; +import kotlinx.coroutines.flow.FlowKt; import java.util.Arrays; @@ -68,6 +76,8 @@ public class DreamOverlayContainerViewController extends private final DreamOverlayStateController mStateController; private final LowLightTransitionCoordinator mLowLightTransitionCoordinator; private final KeyguardTransitionInteractor mKeyguardTransitionInteractor; + private final ShadeInteractor mShadeInteractor; + private final CommunalInteractor mCommunalInteractor; private final ComplicationHostViewController mComplicationHostViewController; @@ -87,9 +97,10 @@ public class DreamOverlayContainerViewController extends // Main thread handler used to schedule periodic tasks (e.g. burn-in protection updates). private final Handler mHandler; - private final CoroutineDispatcher mMainDispatcher; + private final CoroutineDispatcher mBackgroundDispatcher; private final int mDreamOverlayMaxTranslationY; private final PrimaryBouncerCallbackInteractor mPrimaryBouncerCallbackInteractor; + private final DreamManager mDreamManager; private long mJitterStartTimeMillis; @@ -178,7 +189,7 @@ public class DreamOverlayContainerViewController extends LowLightTransitionCoordinator lowLightTransitionCoordinator, BlurUtils blurUtils, @Main Handler handler, - @Main CoroutineDispatcher mainDispatcher, + @Background CoroutineDispatcher backgroundDispatcher, @Main Resources resources, @Named(DreamOverlayModule.MAX_BURN_IN_OFFSET) int maxBurnInOffset, @Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long @@ -188,18 +199,23 @@ public class DreamOverlayContainerViewController extends DreamOverlayAnimationsController animationsController, DreamOverlayStateController stateController, BouncerlessScrimController bouncerlessScrimController, - KeyguardTransitionInteractor keyguardTransitionInteractor) { + KeyguardTransitionInteractor keyguardTransitionInteractor, + ShadeInteractor shadeInteractor, + CommunalInteractor communalInteractor, + DreamManager dreamManager) { super(containerView); mDreamOverlayContentView = contentView; mStatusBarViewController = statusBarViewController; mBlurUtils = blurUtils; mDreamOverlayAnimationsController = animationsController; mStateController = stateController; + mCommunalInteractor = communalInteractor; mLowLightTransitionCoordinator = lowLightTransitionCoordinator; mBouncerlessScrimController = bouncerlessScrimController; mKeyguardTransitionInteractor = keyguardTransitionInteractor; + mShadeInteractor = shadeInteractor; mComplicationHostViewController = complicationHostViewController; mDreamOverlayMaxTranslationY = resources.getDimensionPixelSize( @@ -211,11 +227,12 @@ public class DreamOverlayContainerViewController extends ViewGroup.LayoutParams.MATCH_PARENT)); mHandler = handler; - mMainDispatcher = mainDispatcher; + mBackgroundDispatcher = backgroundDispatcher; mMaxBurnInOffset = maxBurnInOffset; mBurnInProtectionUpdateInterval = burnInProtectionUpdateInterval; mMillisUntilFullJitter = millisUntilFullJitter; mPrimaryBouncerCallbackInteractor = primaryBouncerCallbackInteractor; + mDreamManager = dreamManager; } @Override @@ -238,11 +255,21 @@ public class DreamOverlayContainerViewController extends mView.getRootSurfaceControl().setTouchableRegion(emptyRegion); emptyRegion.recycle(); - collectFlow( - mView, - mKeyguardTransitionInteractor.isFinishedInStateWhere(KeyguardState::isBouncerState), - isFinished -> mAnyBouncerShowing = isFinished, - mMainDispatcher); + if (dreamHandlesBeingObscured()) { + collectFlow( + mView, + FlowKt.distinctUntilChanged(combineFlows( + mKeyguardTransitionInteractor.isFinishedInStateWhere( + KeyguardState::isBouncerState), + mShadeInteractor.isAnyExpanded(), + mCommunalInteractor.isCommunalShowing(), + (anyBouncerShowing, shadeExpanded, communalShowing) -> { + mAnyBouncerShowing = anyBouncerShowing; + return anyBouncerShowing || shadeExpanded || communalShowing; + })), + mDreamManager::setDreamIsObscured, + mBackgroundDispatcher); + } // Start dream entry animations. Skip animations for low light clock. if (!mStateController.isLowLightActive()) { diff --git a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/domain/interactor/HomeControlsComponentInteractor.kt b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/domain/interactor/HomeControlsComponentInteractor.kt index 74452d1980be..20341389b75d 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/domain/interactor/HomeControlsComponentInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/homecontrols/domain/interactor/HomeControlsComponentInteractor.kt @@ -21,7 +21,6 @@ import android.app.DreamManager import android.content.ComponentName import android.os.PowerManager import android.os.UserHandle -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.common.domain.interactor.PackageChangeInteractor import com.android.systemui.common.shared.model.PackageChangeModel import com.android.systemui.controls.ControlsServiceInfo @@ -36,6 +35,7 @@ import com.android.systemui.util.kotlin.getOrNull import com.android.systemui.util.kotlin.pairwiseBy import com.android.systemui.util.kotlin.sample import com.android.systemui.util.time.SystemClock +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import javax.inject.Inject import kotlin.math.abs import kotlin.time.Duration.Companion.milliseconds @@ -132,7 +132,7 @@ constructor( ?: panels.firstOrNull() item?.panelActivity } - .stateIn(bgScope, SharingStarted.WhileSubscribed(), null) + .stateIn(bgScope, SharingStarted.Eagerly, null) private val taskFragmentFinished = MutableSharedFlow<Long>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java index 95bc514540f5..49be03cb08ad 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java @@ -2739,12 +2739,10 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene protected final void setRotationSuggestionsEnabled(boolean enabled) { try { final int userId = Binder.getCallingUserHandle().getIdentifier(); - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - if (enabled) { - info.setRotationSuggestionDisabled(true); - } - mStatusBarService.disableForUser(info, mToken, mContext.getPackageName(), userId, - "setRotationSuggestionsEnabled"); + final int what = enabled + ? StatusBarManager.DISABLE2_NONE + : StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS; + mStatusBarService.disable2ForUser(what, mToken, mContext.getPackageName(), userId); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index dbaa297b7b43..68a252b2caba 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -37,6 +37,7 @@ import android.provider.Settings; import android.service.notification.ZenModeConfig; import android.text.TextUtils; import android.text.style.StyleSpan; +import android.util.Log; import androidx.core.graphics.drawable.IconCompat; import androidx.slice.Slice; @@ -212,21 +213,27 @@ public class KeyguardSliceProvider extends SliceProvider implements @AnyThread @Override public Slice onBindSlice(Uri sliceUri) { - Trace.beginSection("KeyguardSliceProvider#onBindSlice"); - Slice slice; - synchronized (this) { - ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY); - if (needsMediaLocked()) { - addMediaLocked(builder); - } else { - builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText)); + Slice slice = null; + try { + Trace.beginSection("KeyguardSliceProvider#onBindSlice"); + synchronized (this) { + ListBuilder builder = new ListBuilder(getContext(), mSliceUri, + ListBuilder.INFINITY); + if (needsMediaLocked()) { + addMediaLocked(builder); + } else { + builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText)); + } + addNextAlarmLocked(builder); + addZenModeLocked(builder); + addPrimaryActionLocked(builder); + slice = builder.build(); } - addNextAlarmLocked(builder); - addZenModeLocked(builder); - addPrimaryActionLocked(builder); - slice = builder.build(); + } catch (IllegalStateException e) { + Log.w(TAG, "Could not initialize slice", e); + } finally { + Trace.endSection(); } - Trace.endSection(); return slice; } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index d6fd354d8544..2cda72809a36 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -16,7 +16,6 @@ package com.android.systemui.keyguard; -import static android.app.StatusBarManager.DISABLE2_NONE; import static android.app.StatusBarManager.SESSION_KEYGUARD; import static android.provider.Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT; import static android.provider.Settings.System.LOCKSCREEN_SOUNDS_ENABLED; @@ -3440,12 +3439,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, // unless disable is called to show un-hide it once first if (forceClearFlags) { try { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(flags, - DISABLE2_NONE); - mStatusBarService.disableForUser(info, mStatusBarDisableToken, + mStatusBarService.disableForUser(flags, mStatusBarDisableToken, mContext.getPackageName(), - mSelectedUserInteractor.getSelectedUserId(true), - "adjustStatusBarLocked - force clear flags"); + mSelectedUserInteractor.getSelectedUserId(true)); } catch (RemoteException e) { Log.d(TAG, "Failed to force clear flags", e); } @@ -3471,11 +3467,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } try { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(flags, - DISABLE2_NONE); - mStatusBarService.disableForUser(info, mStatusBarDisableToken, - mContext.getPackageName(), mSelectedUserInteractor.getSelectedUserId(true), - "adjustStatusBarLocked - set disable flags"); + mStatusBarService.disableForUser(flags, mStatusBarDisableToken, + mContext.getPackageName(), + mSelectedUserInteractor.getSelectedUserId(true)); } catch (RemoteException e) { Log.d(TAG, "Failed to set disable flags: " + flags, e); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt index 7f3274c09037..7655d7a89dc3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt @@ -247,7 +247,7 @@ constructor( state: TransitionState ) { if (updateTransitionId != transitionId) { - Log.wtf(TAG, "Attempting to update with old/invalid transitionId: $transitionId") + Log.w(TAG, "Attempting to update with old/invalid transitionId: $transitionId") return } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt new file mode 100644 index 000000000000..80bdc65f9b97 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.data.repository + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.shared.model.KeyguardState +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow + +@SysUISingleton +class LockscreenSceneTransitionRepository @Inject constructor() { + + /** + * This [KeyguardState] will indicate which sub state within KTF should be navigated to when the + * next transition into the Lockscreen scene is started. It will be consumed exactly once and + * after that the state will be set back to [DEFAULT_STATE]. + */ + val nextLockscreenTargetState: MutableStateFlow<KeyguardState> = MutableStateFlow(DEFAULT_STATE) + + companion object { + val DEFAULT_STATE = KeyguardState.LOCKSCREEN + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt index 5a28f7113ebd..9b07675f672c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt @@ -26,6 +26,7 @@ import com.android.systemui.keyguard.KeyguardWmStateRefactor import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine import com.android.wm.shell.animation.Interpolators import javax.inject.Inject @@ -140,6 +141,8 @@ constructor( } private fun listenForAlternateBouncerToGone() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return if (KeyguardWmStateRefactor.isEnabled) { // Handled via #dismissAlternateBouncer. return @@ -162,6 +165,8 @@ constructor( } private fun listenForAlternateBouncerToPrimaryBouncer() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return scope.launch { keyguardInteractor.primaryBouncerShowing .filterRelevantKeyguardStateAnd { isPrimaryBouncerShowing -> 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 4d737749fbc1..a306954b7d8f 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 @@ -28,6 +28,7 @@ import com.android.systemui.keyguard.shared.model.BiometricUnlockMode.Companion. import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.Utils.Companion.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -185,6 +186,7 @@ constructor( * PRIMARY_BOUNCER. */ private fun listenForAodToPrimaryBouncer() { + if (SceneContainerFlag.isEnabled) return scope.launch("$TAG#listenForAodToPrimaryBouncer") { keyguardInteractor.primaryBouncerShowing .filterRelevantKeyguardStateAnd { primaryBouncerShowing -> primaryBouncerShowing } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt index e738ea4397de..63294f7609a2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt @@ -26,6 +26,7 @@ import com.android.systemui.keyguard.shared.model.BiometricUnlockMode import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -93,6 +94,8 @@ constructor( } private fun listenForDreamingLockscreenHostedToPrimaryBouncer() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return scope.launch { keyguardInteractor.primaryBouncerShowing .filterRelevantKeyguardStateAnd { isBouncerShowing -> isBouncerShowing } @@ -101,6 +104,8 @@ constructor( } private fun listenForDreamingLockscreenHostedToGone() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return scope.launch { keyguardInteractor.biometricUnlockState .filterRelevantKeyguardStateAnd { biometricUnlockState -> 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 c952e0879d12..7961b45830d4 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 @@ -29,6 +29,7 @@ import com.android.systemui.keyguard.shared.model.BiometricUnlockMode import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine import com.android.systemui.util.kotlin.sample import javax.inject.Inject @@ -88,6 +89,8 @@ constructor( private fun listenForDreamingToGlanceableHub() { if (!communalHub()) return + if (SceneContainerFlag.isEnabled) + return // TODO(b/336576536): Check if adaptation for scene framework is needed scope.launch("$TAG#listenForDreamingToGlanceableHub", mainDispatcher) { glanceableHubTransitions.listenForGlanceableHubTransition( transitionOwnerName = TAG, @@ -175,6 +178,8 @@ constructor( } private fun listenForDreamingToGoneWhenDismissable() { + if (SceneContainerFlag.isEnabled) + return // TODO(b/336576536): Check if adaptation for scene framework is needed scope.launch { keyguardInteractor.isAbleToDream .sampleCombine( @@ -190,6 +195,8 @@ constructor( } private fun listenForDreamingToGoneFromBiometricUnlock() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return scope.launch { keyguardInteractor.biometricUnlockState .filterRelevantKeyguardStateAnd { biometricUnlockState -> diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt index faab033441c1..ca6ab3ef52d8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt @@ -28,9 +28,11 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf import com.android.systemui.util.kotlin.BooleanFlowOperators.not import javax.inject.Inject +import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope @@ -62,6 +64,8 @@ constructor( ) { override fun start() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return if (!Flags.communalHub()) { return } @@ -79,6 +83,7 @@ constructor( duration = when (toState) { KeyguardState.LOCKSCREEN -> TO_LOCKSCREEN_DURATION + KeyguardState.OCCLUDED -> TO_OCCLUDED_DURATION else -> DEFAULT_DURATION }.inWholeMilliseconds } @@ -171,5 +176,6 @@ constructor( const val TAG = "FromGlanceableHubTransitionInteractor" val DEFAULT_DURATION = 1.seconds val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION + val TO_OCCLUDED_DURATION = 450.milliseconds } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt index c2c095bb9574..2b3732f75812 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt @@ -29,6 +29,7 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -62,6 +63,8 @@ constructor( ) { override fun start() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return listenForGoneToAodOrDozing() listenForGoneToDreaming() listenForGoneToLockscreenOrHub() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt index 56261e0865e1..dad2d9692dbc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt @@ -20,6 +20,7 @@ import android.animation.ValueAnimator import android.util.MathUtils import com.android.app.animation.Interpolators import com.android.app.tracing.coroutines.launch +import com.android.systemui.Flags import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main @@ -32,6 +33,7 @@ import com.android.systemui.keyguard.shared.model.TransitionInfo import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.shade.data.repository.ShadeRepository import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine import java.util.UUID @@ -150,6 +152,7 @@ constructor( } private fun listenForLockscreenToPrimaryBouncer() { + if (SceneContainerFlag.isEnabled) return scope.launch("$TAG#listenForLockscreenToPrimaryBouncer") { keyguardInteractor.primaryBouncerShowing .filterRelevantKeyguardStateAnd { isBouncerShowing -> isBouncerShowing } @@ -174,6 +177,7 @@ constructor( /* Starts transitions when manually dragging up the bouncer from the lockscreen. */ private fun listenForLockscreenToPrimaryBouncerDragging() { + if (SceneContainerFlag.isEnabled) return var transitionId: UUID? = null scope.launch("$TAG#listenForLockscreenToPrimaryBouncerDragging") { shadeRepository.legacyShadeExpansion @@ -280,6 +284,7 @@ constructor( } private fun listenForLockscreenToGoneDragging() { + if (SceneContainerFlag.isEnabled) return if (KeyguardWmStateRefactor.isEnabled) { // When the refactor is enabled, we no longer use isKeyguardGoingAway. scope.launch("$TAG#listenForLockscreenToGoneDragging") { @@ -337,7 +342,9 @@ constructor( * keyguard transition. */ private fun listenForLockscreenToGlanceableHub() { - if (!com.android.systemui.Flags.communalHub()) { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return + if (!Flags.communalHub()) { return } scope.launch(mainDispatcher) { diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt index 2a7178f5e24f..2603aab2781b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt @@ -27,6 +27,7 @@ import com.android.systemui.keyguard.KeyguardWmStateRefactor import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.Utils.Companion.sample import com.android.systemui.util.kotlin.sample import javax.inject.Inject @@ -91,20 +92,14 @@ constructor( .sample( communalInteractor.isIdleOnCommunal, communalInteractor.showCommunalFromOccluded, - communalInteractor.dreamFromOccluded + communalInteractor.dreamFromOccluded, ) .collect { (_, isIdleOnCommunal, showCommunalFromOccluded, dreamFromOccluded) -> - // Occlusion signals come from the framework, and should interrupt any - // existing transition - val to = - if (restartDreamOnUnocclude() && dreamFromOccluded) { - KeyguardState.DREAMING - } else if (isIdleOnCommunal || showCommunalFromOccluded) { - KeyguardState.GLANCEABLE_HUB - } else { - KeyguardState.LOCKSCREEN - } - startTransitionTo(to) + startTransitionToLockscreenOrHub( + isIdleOnCommunal, + showCommunalFromOccluded, + dreamFromOccluded + ) } } } else { @@ -121,23 +116,35 @@ constructor( } .collect { (_, _, isIdleOnCommunal, showCommunalFromOccluded, dreamFromOccluded) -> - // Occlusion signals come from the framework, and should interrupt any - // existing transition - val to = - if (restartDreamOnUnocclude() && dreamFromOccluded) { - KeyguardState.DREAMING - } else if (isIdleOnCommunal || showCommunalFromOccluded) { - KeyguardState.GLANCEABLE_HUB - } else { - KeyguardState.LOCKSCREEN - } - startTransitionTo(to) + startTransitionToLockscreenOrHub( + isIdleOnCommunal, + showCommunalFromOccluded, + dreamFromOccluded + ) } } } } + private suspend fun FromOccludedTransitionInteractor.startTransitionToLockscreenOrHub( + isIdleOnCommunal: Boolean, + showCommunalFromOccluded: Boolean, + dreamFromOccluded: Boolean, + ) { + if (restartDreamOnUnocclude() && dreamFromOccluded) { + startTransitionTo(KeyguardState.DREAMING) + } else if (isIdleOnCommunal || showCommunalFromOccluded) { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return + startTransitionTo(KeyguardState.GLANCEABLE_HUB) + } else { + startTransitionTo(KeyguardState.LOCKSCREEN) + } + } + private fun listenForOccludedToGone() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return if (KeyguardWmStateRefactor.isEnabled) { // We don't think OCCLUDED to GONE is possible. You should always have to go via a // *_BOUNCER state to end up GONE. Launching an activity over a dismissable keyguard @@ -158,10 +165,6 @@ constructor( } } - fun dismissToGone() { - scope.launch { startTransitionTo(KeyguardState.GONE) } - } - private fun listenForOccludedToAsleep() { scope.launch { listenForSleepTransition() } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt index 181a551b0537..53a0c3200f3d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt @@ -28,6 +28,7 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled import com.android.systemui.power.domain.interactor.PowerInteractor +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.user.domain.interactor.SelectedUserInteractor import com.android.systemui.util.kotlin.Utils.Companion.sample import com.android.systemui.util.kotlin.sample @@ -98,6 +99,8 @@ constructor( } private fun listenForPrimaryBouncerToLockscreenHubOrOccluded() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return if (KeyguardWmStateRefactor.isEnabled) { scope.launch { keyguardInteractor.primaryBouncerShowing @@ -158,10 +161,14 @@ constructor( } private fun listenForPrimaryBouncerToAsleep() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return scope.launch { listenForSleepTransition() } } private fun listenForPrimaryBouncerToDreamingLockscreenHosted() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return scope.launch { keyguardInteractor.primaryBouncerShowing .sample(keyguardInteractor.isActiveDreamLockscreenHosted, ::Pair) @@ -174,6 +181,8 @@ constructor( } private fun listenForPrimaryBouncerToGone() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return if (KeyguardWmStateRefactor.isEnabled) { // This is handled in KeyguardSecurityContainerController and // StatusBarKeyguardViewManager, which calls the transition interactor to kick off a diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt index 197221a7b5b3..fcf67d519cae 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GlanceableHubTransitions.kt @@ -25,6 +25,7 @@ import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepositor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionInfo import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.sample import java.util.UUID import javax.inject.Inject @@ -49,6 +50,8 @@ constructor( fromState: KeyguardState, toState: KeyguardState, ) { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return val toScene = if (fromState == KeyguardState.GLANCEABLE_HUB) { CommunalScenes.Blank 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 2d7b7375f625..72857391793f 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 @@ -97,6 +97,7 @@ constructor( /** Bounds of the notification container. */ val notificationContainerBounds: StateFlow<NotificationContainerBounds> by lazy { + SceneContainerFlag.assertInLegacyMode() combine( _notificationPlaceholderBounds, sharedNotificationContainerInteractor.get().configurationBasedDimensions, @@ -115,6 +116,7 @@ constructor( } fun setNotificationContainerBounds(position: NotificationContainerBounds) { + SceneContainerFlag.assertInLegacyMode() _notificationPlaceholderBounds.value = position } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt index a18579d9c8e0..8f9a709801ae 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt @@ -17,6 +17,8 @@ package com.android.systemui.keyguard.domain.interactor +import android.annotation.FloatRange +import android.annotation.SuppressLint import android.util.Log import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -28,12 +30,13 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCE import com.android.systemui.keyguard.shared.model.KeyguardState.AOD import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN -import com.android.systemui.keyguard.shared.model.KeyguardState.OFF import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER import com.android.systemui.keyguard.shared.model.TransitionInfo import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.kotlin.pairwise +import java.util.UUID import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -76,6 +79,8 @@ constructor( * single state. This prevent the redundant filters from running. */ private val transitionValueCache = mutableMapOf<KeyguardState, MutableSharedFlow<Float>>() + + @SuppressLint("SharedFlowCreation") private fun getTransitionValueFlow(state: KeyguardState): MutableSharedFlow<Float> { return transitionValueCache.getOrPut(state) { MutableSharedFlow<Float>( @@ -90,6 +95,9 @@ constructor( @Deprecated("Not performant - Use something else in this class") val transitions = repository.transitions + val transitionState: StateFlow<TransitionStep> = + transitions.stateIn(scope, SharingStarted.Eagerly, TransitionStep()) + /** * A pair of the most recent STARTED step, and the transition step immediately preceding it. The * transition framework enforces that the previous step is either a CANCELED or FINISHED step, @@ -99,6 +107,7 @@ constructor( * FINISHED. In the case of a CANCELED step, we can also figure out which state we were coming * from when we were canceled. */ + @SuppressLint("SharedFlowCreation") val startedStepWithPrecedingStep = repository.transitions .pairwise() @@ -144,9 +153,10 @@ constructor( } /** Given an [edge], return a SharedFlow to collect only relevant [TransitionStep]. */ + @SuppressLint("SharedFlowCreation") fun getOrCreateFlow(edge: Edge): MutableSharedFlow<TransitionStep> { return transitionMap.getOrPut(edge) { - MutableSharedFlow<TransitionStep>( + MutableSharedFlow( extraBufferCapacity = 10, onBufferOverflow = BufferOverflow.DROP_OLDEST ) @@ -180,6 +190,7 @@ constructor( * AOD<->* transition information, mapped to dozeAmount range of AOD (1f) <-> * * (0f). */ + @SuppressLint("SharedFlowCreation") val dozeAmountTransition: Flow<TransitionStep> = repository.transitions .filter { step -> step.from == AOD || step.to == AOD } @@ -201,11 +212,22 @@ constructor( repository.transitions.filter { step -> step.transitionState == TransitionState.FINISHED } /** The destination state of the last [TransitionState.STARTED] transition. */ + @SuppressLint("SharedFlowCreation") val startedKeyguardState: SharedFlow<KeyguardState> = startedKeyguardTransitionStep .map { step -> step.to } .shareIn(scope, SharingStarted.Eagerly, replay = 1) + val currentTransitionInfo: StateFlow<TransitionInfo> = repository.currentTransitionInfoInternal + + /** The from state of the last [TransitionState.STARTED] transition. */ + // TODO: is it performant to have several SharedFlows side by side instead of one? + @SuppressLint("SharedFlowCreation") + val startedKeyguardFromState: SharedFlow<KeyguardState> = + startedKeyguardTransitionStep + .map { step -> step.from } + .shareIn(scope, SharingStarted.Eagerly, replay = 1) + /** Which keyguard state to use when the device goes to sleep. */ val asleepKeyguardState: StateFlow<KeyguardState> = keyguardRepository.isAodAvailable @@ -243,6 +265,7 @@ constructor( * sufficient. However, if you're having issues with state *during* transitions started after * one or more canceled transitions, you probably need to use [currentKeyguardState]. */ + @SuppressLint("SharedFlowCreation") val finishedKeyguardState: SharedFlow<KeyguardState> = finishedKeyguardTransitionStep .map { step -> step.to } @@ -356,6 +379,8 @@ constructor( * state. */ fun startDismissKeyguardTransition() { + // TODO(b/336576536): Check if adaptation for scene framework is needed + if (SceneContainerFlag.isEnabled) return when (val startedState = startedKeyguardState.replayCache.last()) { LOCKSCREEN -> fromLockscreenTransitionInteractor.get().dismissKeyguard() PRIMARY_BOUNCER -> fromPrimaryBouncerTransitionInteractor.get().dismissPrimaryBouncer() @@ -489,7 +514,19 @@ constructor( return startedKeyguardState.replayCache.last() } + fun getStartedFromState(): KeyguardState { + return startedKeyguardFromState.replayCache.last() + } + fun getFinishedState(): KeyguardState { return finishedKeyguardState.replayCache.last() } + + suspend fun startTransition(info: TransitionInfo) = repository.startTransition(info) + + fun updateTransition( + transitionId: UUID, + @FloatRange(from = 0.0, to = 1.0) value: Float, + state: TransitionState + ) = repository.updateTransition(transitionId, value, state) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt index 2d944c694310..9443570705c8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt @@ -103,6 +103,7 @@ constructor( KeyguardState.LOCKSCREEN -> true KeyguardState.GONE -> true KeyguardState.OCCLUDED -> true + KeyguardState.UNDEFINED -> true } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt index d95c38e2697c..3c661861efd2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt @@ -16,6 +16,7 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.CoreStartable +import com.android.systemui.keyguard.domain.interactor.scenetransition.LockscreenSceneTransitionInteractor import dagger.Binds import dagger.Module import dagger.multibindings.ClassKey @@ -31,6 +32,13 @@ abstract class StartKeyguardTransitionModule { abstract fun bind(impl: KeyguardTransitionCoreStartable): CoreStartable @Binds + @IntoMap + @ClassKey(LockscreenSceneTransitionInteractor::class) + abstract fun bindLockscreenSceneTransitionInteractor( + impl: LockscreenSceneTransitionInteractor + ): CoreStartable + + @Binds @IntoSet abstract fun fromPrimaryBouncer( impl: FromPrimaryBouncerTransitionInteractor diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt index bb2eeb77969d..dc35e4311d25 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractor.kt @@ -16,11 +16,16 @@ package com.android.systemui.keyguard.domain.interactor +import com.android.compose.animation.scene.ObservableTransitionState import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.BiometricUnlockMode import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState +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 com.android.systemui.statusbar.notification.domain.interactor.NotificationLaunchAnimationInteractor +import com.android.systemui.util.kotlin.pairwise import com.android.systemui.util.kotlin.sample import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -42,6 +47,7 @@ constructor( fromBouncerInteractor: FromPrimaryBouncerTransitionInteractor, fromAlternateBouncerInteractor: FromAlternateBouncerTransitionInteractor, notificationLaunchAnimationInteractor: NotificationLaunchAnimationInteractor, + sceneInteractor: SceneInteractor, ) { private val defaultSurfaceBehindVisibility = transitionInteractor.finishedKeyguardState.map(::isSurfaceVisible) @@ -103,21 +109,42 @@ constructor( * animation. This is used to keep the RemoteAnimationTarget alive until we're done using it. */ val usingKeyguardGoingAwayAnimation: Flow<Boolean> = - combine( - transitionInteractor.isInTransitionToState(KeyguardState.GONE), - transitionInteractor.finishedKeyguardState, - surfaceBehindInteractor.isAnimatingSurface, - notificationLaunchAnimationInteractor.isLaunchAnimationRunning, - ) { isInTransitionToGone, finishedState, isAnimatingSurface, notifLaunchRunning -> - // Using the animation if we're animating it directly, or if the - // ActivityLaunchAnimator is in the process of animating it. - val animationsRunning = isAnimatingSurface || notifLaunchRunning - // We may still be animating the surface after the keyguard is fully GONE, since - // some animations (like the translation spring) are not tied directly to the - // transition step amount. - isInTransitionToGone || (finishedState == KeyguardState.GONE && animationsRunning) - } - .distinctUntilChanged() + if (SceneContainerFlag.isEnabled) { + combine( + sceneInteractor.transitionState, + surfaceBehindInteractor.isAnimatingSurface, + notificationLaunchAnimationInteractor.isLaunchAnimationRunning, + ) { transition, isAnimatingSurface, isLaunchAnimationRunning -> + // Using the animation if we're animating it directly, or if the + // ActivityLaunchAnimator is in the process of animating it. + val isAnyAnimationRunning = isAnimatingSurface || isLaunchAnimationRunning + // We may still be animating the surface after the keyguard is fully GONE, since + // some animations (like the translation spring) are not tied directly to the + // transition step amount. + transition.isTransitioning(to = Scenes.Gone) || + (isAnyAnimationRunning && + (transition.isIdle(Scenes.Gone) || + transition.isTransitioning(from = Scenes.Gone))) + } + .distinctUntilChanged() + } else { + combine( + transitionInteractor.isInTransitionToState(KeyguardState.GONE), + transitionInteractor.finishedKeyguardState, + surfaceBehindInteractor.isAnimatingSurface, + notificationLaunchAnimationInteractor.isLaunchAnimationRunning, + ) { isInTransitionToGone, finishedState, isAnimatingSurface, notifLaunchRunning -> + // Using the animation if we're animating it directly, or if the + // ActivityLaunchAnimator is in the process of animating it. + val animationsRunning = isAnimatingSurface || notifLaunchRunning + // We may still be animating the surface after the keyguard is fully GONE, since + // some animations (like the translation spring) are not tied directly to the + // transition step amount. + isInTransitionToGone || + (finishedState == KeyguardState.GONE && animationsRunning) + } + .distinctUntilChanged() + } /** * Whether the lockscreen is visible, from the Window Manager (WM) perspective. @@ -127,28 +154,44 @@ constructor( * want to know if the AOD/clock/notifs/etc. are visible. */ val lockscreenVisibility: Flow<Boolean> = - transitionInteractor.currentKeyguardState - .sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair) - .map { (currentState, startedWithPrev) -> - val startedFromStep = startedWithPrev?.previousValue - val startedStep = startedWithPrev?.newValue - val returningToGoneAfterCancellation = - startedStep?.to == KeyguardState.GONE && - startedFromStep?.transitionState == TransitionState.CANCELED && - startedFromStep.from == KeyguardState.GONE + if (SceneContainerFlag.isEnabled) { + sceneInteractor.transitionState + .pairwise(ObservableTransitionState.Idle(Scenes.Lockscreen)) + .map { (prevTransitionState, transitionState) -> + val isReturningToGoneAfterCancellation = + prevTransitionState.isTransitioning(from = Scenes.Gone) && + transitionState.isTransitioning(to = Scenes.Gone) + val isNotOnGone = + !transitionState.isTransitioning(from = Scenes.Gone) && + !transitionState.isIdle(Scenes.Gone) - if (!returningToGoneAfterCancellation) { - // By default, apply the lockscreen visibility of the current state. - KeyguardState.lockscreenVisibleInState(currentState) - } else { - // If we're transitioning to GONE after a prior canceled transition from GONE, - // then this is the camera launch transition from an asleep state back to GONE. - // We don't want to show the lockscreen since we're aborting the lock and going - // back to GONE. - KeyguardState.lockscreenVisibleInState(KeyguardState.GONE) + isNotOnGone && !isReturningToGoneAfterCancellation } - } - .distinctUntilChanged() + .distinctUntilChanged() + } else { + transitionInteractor.currentKeyguardState + .sample(transitionInteractor.startedStepWithPrecedingStep, ::Pair) + .map { (currentState, startedWithPrev) -> + val startedFromStep = startedWithPrev?.previousValue + val startedStep = startedWithPrev?.newValue + val returningToGoneAfterCancellation = + startedStep?.to == KeyguardState.GONE && + startedFromStep?.transitionState == TransitionState.CANCELED && + startedFromStep.from == KeyguardState.GONE + + if (!returningToGoneAfterCancellation) { + // By default, apply the lockscreen visibility of the current state. + KeyguardState.lockscreenVisibleInState(currentState) + } else { + // If we're transitioning to GONE after a prior canceled transition from + // GONE, then this is the camera launch transition from an asleep state back + // to GONE. We don't want to show the lockscreen since we're aborting the + // lock and going back to GONE. + KeyguardState.lockscreenVisibleInState(KeyguardState.GONE) + } + } + .distinctUntilChanged() + } /** * Whether always-on-display (AOD) is visible when the lockscreen is visible, from window diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt new file mode 100644 index 000000000000..3baeb7682e12 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt @@ -0,0 +1,231 @@ +/* + * 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.domain.interactor.scenetransition + +import com.android.compose.animation.scene.ObservableTransitionState +import com.android.compose.animation.scene.SceneKey +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyguard.data.repository.LockscreenSceneTransitionRepository +import com.android.systemui.keyguard.data.repository.LockscreenSceneTransitionRepository.Companion.DEFAULT_STATE +import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.KeyguardState.UNDEFINED +import com.android.systemui.keyguard.shared.model.TransitionInfo +import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled +import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED +import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING +import com.android.systemui.scene.domain.interactor.SceneInteractor +import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.util.kotlin.pairwise +import java.util.UUID +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch + +/** + * This class listens to scene framework scene transitions and manages keyguard transition framework + * (KTF) states accordingly. + * + * There are a few rules: + * - When scene framework is on a scene outside of Lockscreen, then KTF is in state UNDEFINED + * - When scene framework is on Lockscreen, KTF is allowed to change its scenes freely + * - When scene framework is transitioning away from Lockscreen, then KTF transitions to UNDEFINED + * and shares its progress. + * - When scene framework is transitioning to Lockscreen, then KTF starts a transition to LOCKSCREEN + * but it is allowed to interrupt this transition and transition to other internal KTF states + * + * There are a few notable differences between SceneTransitionLayout (STL) and KTF that require + * special treatment when synchronizing both state machines. + * - STL does not emit cancelations as KTF does + * - Both STL and KTF require state continuity, though the rules from where starting the next + * transition is allowed is different on each side: + * - STL has a concept of "currentScene" which can be chosen to be either A or B in a A -> B + * transition. The currentScene determines which transition can be started next. In KTF the + * currentScene is always the `to` state. Which means transitions can only be started from B. + * This also holds true when A -> B was canceled: the next transition needs to start from B. + * - KTF can not settle back in its from scene, instead it needs to cancel and start a reversed + * transition. + */ +@SysUISingleton +class LockscreenSceneTransitionInteractor +@Inject +constructor( + val transitionInteractor: KeyguardTransitionInteractor, + @Application private val applicationScope: CoroutineScope, + private val sceneInteractor: SceneInteractor, + private val repository: LockscreenSceneTransitionRepository, +) : CoreStartable, SceneInteractor.OnSceneAboutToChangeListener { + + private var currentTransitionId: UUID? = null + private var progressJob: Job? = null + + override fun start() { + sceneInteractor.registerSceneStateProcessor(this) + listenForSceneTransitionProgress() + } + + override fun onSceneAboutToChange(toScene: SceneKey, sceneState: Any?) { + if (toScene != Scenes.Lockscreen || sceneState == null) return + if (sceneState !is KeyguardState) { + throw IllegalArgumentException("Lockscreen sceneState needs to be a KeyguardState.") + } + repository.nextLockscreenTargetState.value = sceneState + } + + private fun listenForSceneTransitionProgress() { + applicationScope.launch { + sceneInteractor.transitionState + .pairwise(ObservableTransitionState.Idle(Scenes.Lockscreen)) + .collect { (prevTransition, transition) -> + when (transition) { + is ObservableTransitionState.Idle -> handleIdle(prevTransition, transition) + is ObservableTransitionState.Transition -> handleTransition(transition) + } + } + } + } + + private suspend fun handleIdle( + prevTransition: ObservableTransitionState, + idle: ObservableTransitionState.Idle + ) { + if (currentTransitionId == null) return + if (prevTransition !is ObservableTransitionState.Transition) return + + if (idle.currentScene == prevTransition.toScene) { + finishCurrentTransition() + } else { + val targetState = + if (idle.currentScene == Scenes.Lockscreen) { + transitionInteractor.getStartedFromState() + } else { + UNDEFINED + } + finishReversedTransitionTo(targetState) + } + } + + private fun finishCurrentTransition() { + transitionInteractor.updateTransition(currentTransitionId!!, 1f, FINISHED) + resetTransitionData() + } + + private suspend fun finishReversedTransitionTo(state: KeyguardState) { + val newTransition = + TransitionInfo( + ownerName = this::class.java.simpleName, + from = transitionInteractor.currentTransitionInfo.value.to, + to = state, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.REVERSE + ) + currentTransitionId = transitionInteractor.startTransition(newTransition) + transitionInteractor.updateTransition(currentTransitionId!!, 1f, FINISHED) + resetTransitionData() + } + + private fun resetTransitionData() { + progressJob?.cancel() + progressJob = null + currentTransitionId = null + } + + private suspend fun handleTransition(transition: ObservableTransitionState.Transition) { + if (transition.fromScene == Scenes.Lockscreen) { + if (currentTransitionId != null) { + val currentToState = transitionInteractor.currentTransitionInfo.value.to + if (currentToState == UNDEFINED) { + transitionKtfTo(transitionInteractor.getStartedFromState()) + } + } + startTransitionFromLockscreen() + collectProgress(transition) + } else if (transition.toScene == Scenes.Lockscreen) { + if (currentTransitionId != null) { + transitionKtfTo(UNDEFINED) + } + startTransitionToLockscreen() + collectProgress(transition) + } else { + transitionKtfTo(UNDEFINED) + } + } + + private suspend fun transitionKtfTo(state: KeyguardState) { + // TODO(b/330311871): This is based on a sharedFlow and thus might not be up-to-date and + // cause a race condition. (There is no known scenario that is currently affected.) + val currentTransition = transitionInteractor.transitionState.value + if (currentTransition.isFinishedIn(state)) { + // This is already the state we want to be in + resetTransitionData() + } else if (currentTransition.isTransitioning(to = state)) { + finishCurrentTransition() + } else { + finishReversedTransitionTo(state) + } + } + + private fun collectProgress(transition: ObservableTransitionState.Transition) { + progressJob?.cancel() + progressJob = applicationScope.launch { transition.progress.collect { updateProgress(it) } } + } + + private suspend fun startTransitionToLockscreen() { + val newTransition = + TransitionInfo( + ownerName = this::class.java.simpleName, + from = UNDEFINED, + to = repository.nextLockscreenTargetState.value, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + repository.nextLockscreenTargetState.value = DEFAULT_STATE + startTransition(newTransition) + } + + private suspend fun startTransitionFromLockscreen() { + val currentState = transitionInteractor.currentTransitionInfo.value.to + val newTransition = + TransitionInfo( + ownerName = this::class.java.simpleName, + from = currentState, + to = UNDEFINED, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + startTransition(newTransition) + } + + private suspend fun startTransition(transitionInfo: TransitionInfo) { + if (currentTransitionId != null) { + resetTransitionData() + } + currentTransitionId = transitionInteractor.startTransition(transitionInfo) + } + + private fun updateProgress(progress: Float) { + if (currentTransitionId == null) return + transitionInteractor.updateTransition( + currentTransitionId!!, + progress.coerceIn(0f, 1f), + RUNNING + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt index 7d0553937f25..6d96db34e23a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt @@ -17,7 +17,7 @@ package com.android.systemui.keyguard.shared.model /** List of all possible states to transition to/from */ enum class KeyguardState { - /* + /** * The display is completely off, as well as any sensors that would trigger the device to wake * up. */ @@ -29,13 +29,13 @@ enum class KeyguardState { * notifications is enabled, allowing the device to quickly wake up. */ DOZING, - /* + /** * A device state after the device times out, which can be from both LOCKSCREEN or GONE states. * DOZING is an example of special version of this state. Dreams may be implemented by third * parties to present their own UI over keyguard, like a screensaver. */ DREAMING, - /* + /** * A device state after the device times out, which can be from both LOCKSCREEN or GONE states. * It is a special version of DREAMING state but not DOZING. The active dream will be windowless * and hosted in the lockscreen. @@ -47,17 +47,17 @@ enum class KeyguardState { * low-power mode without a UI, then it is DOZING. */ AOD, - /* + /** * The security screen prompt containing UI to prompt the user to use a biometric credential * (ie: fingerprint). When supported, this may show before showing the primary bouncer. */ ALTERNATE_BOUNCER, - /* + /** * The security screen prompt UI, containing PIN, Password, Pattern for the user to verify their * credentials. */ PRIMARY_BOUNCER, - /* + /** * Device is actively displaying keyguard UI and is not in low-power mode. Device may be * unlocked if SWIPE security method is used, or if face lockscreen bypass is false. */ @@ -68,15 +68,20 @@ enum class KeyguardState { * or dream, as well as swipe down for the notifications and up for the bouncer. */ GLANCEABLE_HUB, - /* - * Keyguard is no longer visible. In most cases the user has just authenticated and keyguard - * is being removed, but there are other cases where the user is swiping away keyguard, such as + /** + * Keyguard is no longer visible. In most cases the user has just authenticated and keyguard is + * being removed, but there are other cases where the user is swiping away keyguard, such as * with SWIPE security method or face unlock without bypass. */ GONE, - /* - * An activity is displaying over the keyguard. + /** + * Only used in scene framework. This means we are currently on any scene framework scene that + * is not Lockscreen. Transitions to and from UNDEFINED are always bound to the + * [SceneTransitionLayout] scene transition that either transitions to or from the Lockscreen + * scene. These transitions are automatically handled by [LockscreenSceneTransitionInteractor]. */ + UNDEFINED, + /** An activity is displaying over the keyguard. */ OCCLUDED; companion object { @@ -109,6 +114,7 @@ enum class KeyguardState { LOCKSCREEN -> true GONE -> true OCCLUDED -> true + UNDEFINED -> true } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt index 0fa6f4fa4f0b..2b4c4af98ccd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/TransitionStep.kt @@ -30,4 +30,12 @@ constructor( value: Float, transitionState: TransitionState, ) : this(info.from, info.to, value, transitionState, info.ownerName) + + fun isTransitioning(from: KeyguardState? = null, to: KeyguardState? = null): Boolean { + return (from == null || this.from == from) && (to == null || this.to == to) + } + + fun isFinishedIn(state: KeyguardState): Boolean { + return to == state && transitionState == TransitionState.FINISHED + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt index e2b66c595e3e..1c7b4d996b36 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/DeviceEntryIconViewBinder.kt @@ -22,6 +22,8 @@ import android.content.res.ColorStateList import android.util.StateSet import android.view.HapticFeedbackConstants import android.view.View +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb import androidx.core.view.isInvisible import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle @@ -61,6 +63,7 @@ object DeviceEntryIconViewBinder { bgViewModel: DeviceEntryBackgroundViewModel, falsingManager: FalsingManager, vibratorHelper: VibratorHelper, + overrideColor: Color? = null, ) { DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode() val longPressHandlingView = view.longPressHandlingView @@ -168,7 +171,8 @@ object DeviceEntryIconViewBinder { viewModel.type.contentDescriptionResId ) } - fgIconView.imageTintList = ColorStateList.valueOf(viewModel.tint) + fgIconView.imageTintList = + ColorStateList.valueOf(overrideColor?.toArgb() ?: viewModel.tint) fgIconView.setPadding( viewModel.padding, viewModel.padding, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt index ed5d53cc9371..c846cbe76770 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinder.kt @@ -33,14 +33,18 @@ import com.android.systemui.keyguard.shared.model.ClockSize import com.android.systemui.keyguard.ui.view.layout.blueprints.transitions.IntraBlueprintTransition.Type import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel +import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.plugins.clocks.AodClockBurnInModel import com.android.systemui.plugins.clocks.ClockController +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch object KeyguardClockViewBinder { private val TAG = KeyguardClockViewBinder::class.simpleName!! // When changing to new clock, we need to remove old clock views from burnInLayer private var lastClock: ClockController? = null + @JvmStatic fun bind( clockSection: ClockSection, @@ -48,6 +52,7 @@ object KeyguardClockViewBinder { viewModel: KeyguardClockViewModel, keyguardClockInteractor: KeyguardClockInteractor, blueprintInteractor: KeyguardBlueprintInteractor, + rootViewModel: KeyguardRootViewModel, ) { keyguardRootView.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { @@ -105,6 +110,28 @@ object KeyguardClockViewBinder { } } } + + launch { + if (!MigrateClocksToBlueprint.isEnabled) return@launch + combine( + rootViewModel.translationX, + rootViewModel.translationY, + rootViewModel.scale, + ::Triple + ) + .collect { (translationX, translationY, scale) -> + viewModel.currentClock.value + ?.largeClock + ?.layout + ?.applyAodBurnIn( + AodClockBurnInModel( + translationX = translationX.value!!, + translationY = translationY, + scale = scale.scale + ) + ) + } + } } } } @@ -117,17 +144,16 @@ object KeyguardClockViewBinder { ) { val burnInLayer = viewModel.burnInLayer val clockController = viewModel.currentClock.value + // Large clocks won't be added to or removed from burn in layer + // Weather large clock has customized burn in preventing mechanism + // Non-weather large clock will only scale and translate vertically clockController?.let { clock -> when (clockSize) { ClockSize.LARGE -> { clock.smallClock.layout.views.forEach { burnInLayer?.removeView(it) } - if (clock.config.useAlternateSmartspaceAODTransition) { - clock.largeClock.layout.views.forEach { burnInLayer?.addView(it) } - } } ClockSize.SMALL -> { clock.smallClock.layout.views.forEach { burnInLayer?.addView(it) } - clock.largeClock.layout.views.forEach { burnInLayer?.removeView(it) } } } } @@ -148,13 +174,6 @@ object KeyguardClockViewBinder { burnInLayer?.removeView(it) rootView.removeView(it) } - - // add large clock to burn in layer only when it will have same transition with other - // components in AOD otherwise, it will have a separate scale transition while other - // components only have translate transition - if (clock.config.useAlternateSmartspaceAODTransition) { - clock.largeClock.layout.views.forEach { burnInLayer?.removeView(it) } - } clock.largeClock.layout.views.forEach { rootView.removeView(it) } } lastClock = currentClock diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt index bda6438c308f..39db22d5616d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardRootViewBinder.kt @@ -236,7 +236,8 @@ object KeyguardRootViewBinder { indicationArea, startButton, endButton, - lockIcon -> { + lockIcon, + deviceEntryIcon -> { // Do not move these views } else -> childView.translationX = px @@ -256,23 +257,6 @@ object KeyguardRootViewBinder { it.scaleX = scaleViewModel.scale it.scaleY = scaleViewModel.scale } - // Make sure to reset these views, or they will be invisible - if (childViews[burnInLayerId]?.scaleX != 1f) { - childViews[burnInLayerId]?.scaleX = 1f - childViews[burnInLayerId]?.scaleY = 1f - childViews[aodNotificationIconContainerId]?.scaleX = 1f - childViews[aodNotificationIconContainerId]?.scaleY = 1f - view.requestLayout() - } - } else { - // For weather clock, large clock should have only scale - // transition with other parts in burnInLayer - childViews[burnInLayerId]?.scaleX = scaleViewModel.scale - childViews[burnInLayerId]?.scaleY = scaleViewModel.scale - childViews[aodNotificationIconContainerId]?.scaleX = - scaleViewModel.scale - childViews[aodNotificationIconContainerId]?.scaleY = - scaleViewModel.scale } } } @@ -596,6 +580,7 @@ object KeyguardRootViewBinder { private val startButton = R.id.start_button private val endButton = R.id.end_button private val lockIcon = R.id.lock_icon_view + private val deviceEntryIcon = R.id.device_entry_icon_view private val nsslPlaceholderId = R.id.nssl_placeholder private const val ID = "occluding_app_device_entry_unlock_msg" diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt index 0f63f65e4511..1f4bc61fb003 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/transitions/DeviceEntryIconTransitionModule.kt @@ -29,7 +29,10 @@ import com.android.systemui.keyguard.ui.viewmodel.DozingToLockscreenTransitionVi import com.android.systemui.keyguard.ui.viewmodel.DozingToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DozingToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToAodTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.DreamingToLockscreenTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToAodTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToDozingTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GoneToLockscreenTransitionViewModel @@ -40,6 +43,7 @@ import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGoneTransitionView import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToPrimaryBouncerTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludedToAodTransitionViewModel +import com.android.systemui.keyguard.ui.viewmodel.OccludedToGlanceableHubTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.OffToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.PrimaryBouncerToAodTransitionViewModel @@ -218,4 +222,28 @@ abstract class DeviceEntryIconTransitionModule { abstract fun primaryBouncerToLockscreen( impl: PrimaryBouncerToLockscreenTransitionViewModel ): DeviceEntryIconTransition + + @Binds + @IntoSet + abstract fun dreamingToGlanceableHub( + impl: DreamingToGlanceableHubTransitionViewModel + ): DeviceEntryIconTransition + + @Binds + @IntoSet + abstract fun glanceableHubToDreaming( + impl: GlanceableHubToDreamingTransitionViewModel + ): DeviceEntryIconTransition + + @Binds + @IntoSet + abstract fun glanceableHubToOccluded( + impl: GlanceableHubToOccludedTransitionViewModel + ): DeviceEntryIconTransition + + @Binds + @IntoSet + abstract fun occludedToGlanceableHub( + impl: OccludedToGlanceableHubTransitionViewModel + ): DeviceEntryIconTransition } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt index ef2927096c04..b367715f529e 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSection.kt @@ -38,6 +38,7 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.binder.KeyguardClockViewBinder import com.android.systemui.keyguard.ui.viewmodel.KeyguardClockViewModel +import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFaceLayout @@ -64,6 +65,7 @@ constructor( private val context: Context, val smartspaceViewModel: KeyguardSmartspaceViewModel, val blueprintInteractor: Lazy<KeyguardBlueprintInteractor>, + private val rootViewModel: KeyguardRootViewModel, ) : KeyguardSection() { override fun addViews(constraintLayout: ConstraintLayout) {} override fun bindData(constraintLayout: ConstraintLayout) { @@ -75,7 +77,8 @@ constructor( constraintLayout, keyguardClockViewModel, clockInteractor, - blueprintInteractor.get() + blueprintInteractor.get(), + rootViewModel, ) } 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 218967c338ea..7c745bc227f0 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 @@ -57,9 +57,9 @@ class ClockSizeTransition( addTransition(SmartspaceMoveTransition(config, clockViewModel)) } - open class VisibilityBoundsTransition() : Transition() { - var captureSmartspace: Boolean = false - + abstract class VisibilityBoundsTransition() : Transition() { + abstract val captureSmartspace: Boolean + protected val TAG = this::class.simpleName!! override fun captureEndValues(transition: TransitionValues) = captureValues(transition) override fun captureStartValues(transition: TransitionValues) = captureValues(transition) override fun getTransitionProperties(): Array<String> = TRANSITION_PROPERTIES @@ -76,7 +76,7 @@ class ClockSizeTransition( parent.findViewById<View>(sharedR.id.bc_smartspace_view) ?: parent.findViewById<View>(R.id.keyguard_slice_view) if (targetSSView == null) { - Log.e(TAG, "Failed to find smartspace equivalent target for animation") + Log.e(TAG, "Failed to find smartspace equivalent target under $parent") return } transition.values[SMARTSPACE_BOUNDS] = targetSSView.getRect() @@ -109,14 +109,12 @@ class ClockSizeTransition( var fromIsVis = fromVis == View.VISIBLE var fromAlpha = startValues.values[PROP_ALPHA] as Float val fromBounds = startValues.values[PROP_BOUNDS] as Rect - val fromSSBounds = - if (captureSmartspace) startValues.values[SMARTSPACE_BOUNDS] as Rect else null + 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 = - if (captureSmartspace) endValues.values[SMARTSPACE_BOUNDS] as Rect else null + val toSSBounds = endValues.values[SMARTSPACE_BOUNDS] as Rect? val toIsVis = toVis == View.VISIBLE val toAlpha = if (toIsVis) 1f else 0f @@ -221,9 +219,6 @@ class ClockSizeTransition( private const val SMARTSPACE_BOUNDS = "ClockSizeTransition:SSBounds" private val TRANSITION_PROPERTIES = arrayOf(PROP_VISIBILITY, PROP_ALPHA, PROP_BOUNDS, SMARTSPACE_BOUNDS) - - private val DEBUG = false - private val TAG = VisibilityBoundsTransition::class.simpleName!! } } @@ -232,18 +227,24 @@ class ClockSizeTransition( val viewModel: KeyguardClockViewModel, val smartspaceViewModel: KeyguardSmartspaceViewModel, ) : VisibilityBoundsTransition() { + override val captureSmartspace = !viewModel.isLargeClockVisible.value + init { duration = CLOCK_IN_MILLIS startDelay = CLOCK_IN_START_DELAY_MILLIS interpolator = CLOCK_IN_INTERPOLATOR - captureSmartspace = - !viewModel.isLargeClockVisible.value && smartspaceViewModel.isSmartspaceEnabled if (viewModel.isLargeClockVisible.value) { viewModel.currentClock.value?.let { + if (DEBUG) Log.i(TAG, "Large Clock In: ${it.largeClock.layout.views}") it.largeClock.layout.views.forEach { addTarget(it) } } + ?: run { + Log.e(TAG, "No large clock set, falling back") + addTarget(R.id.lockscreen_clock_view_large) + } } else { + if (DEBUG) Log.i(TAG, "Small Clock In") addTarget(R.id.lockscreen_clock_view) } } @@ -282,7 +283,6 @@ class ClockSizeTransition( val CLOCK_IN_INTERPOLATOR = Interpolators.LINEAR_OUT_SLOW_IN const val SMALL_CLOCK_IN_MOVE_SCALE = CLOCK_IN_MILLIS / SmartspaceMoveTransition.STATUS_AREA_MOVE_DOWN_MILLIS.toFloat() - private val TAG = ClockFaceInTransition::class.simpleName!! } } @@ -291,18 +291,24 @@ class ClockSizeTransition( val viewModel: KeyguardClockViewModel, val smartspaceViewModel: KeyguardSmartspaceViewModel, ) : VisibilityBoundsTransition() { + override val captureSmartspace = viewModel.isLargeClockVisible.value + init { duration = CLOCK_OUT_MILLIS interpolator = CLOCK_OUT_INTERPOLATOR - captureSmartspace = - viewModel.isLargeClockVisible.value && smartspaceViewModel.isSmartspaceEnabled if (viewModel.isLargeClockVisible.value) { + if (DEBUG) Log.i(TAG, "Small Clock Out") addTarget(R.id.lockscreen_clock_view) } else { viewModel.currentClock.value?.let { + if (DEBUG) Log.i(TAG, "Large Clock Out: ${it.largeClock.layout.views}") it.largeClock.layout.views.forEach { addTarget(it) } } + ?: run { + Log.e(TAG, "No large clock set, falling back") + addTarget(R.id.lockscreen_clock_view_large) + } } } @@ -339,7 +345,6 @@ class ClockSizeTransition( val CLOCK_OUT_INTERPOLATOR = Interpolators.LINEAR const val SMALL_CLOCK_OUT_MOVE_SCALE = CLOCK_OUT_MILLIS / SmartspaceMoveTransition.STATUS_AREA_MOVE_UP_MILLIS.toFloat() - private val TAG = ClockFaceOutTransition::class.simpleName!! } } @@ -348,6 +353,8 @@ class ClockSizeTransition( val config: IntraBlueprintTransition.Config, viewModel: KeyguardClockViewModel, ) : VisibilityBoundsTransition() { + override val captureSmartspace = false + init { duration = if (viewModel.isLargeClockVisible.value) STATUS_AREA_MOVE_UP_MILLIS @@ -367,4 +374,8 @@ class ClockSizeTransition( const val STATUS_AREA_MOVE_DOWN_MILLIS = 467L } } + + companion object { + val DEBUG = true + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt index 5b83a10c14c7..c05a1b732a50 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodBurnInViewModel.kt @@ -27,7 +27,6 @@ import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.domain.interactor.BurnInInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor -import com.android.systemui.keyguard.shared.ComposeLockscreen import com.android.systemui.keyguard.shared.model.BurnInModel import com.android.systemui.keyguard.shared.model.ClockSize import com.android.systemui.keyguard.ui.StateToValue @@ -121,11 +120,13 @@ constructor( ), ) { interpolated, burnIn -> val useAltAod = - keyguardClockViewModel.currentClock.value?.let { clock -> - clock.config.useAlternateSmartspaceAODTransition - } == true + keyguardClockViewModel.currentClock.value + ?.config + ?.useAlternateSmartspaceAODTransition == true + // Only scale large non-weather clocks + // elements in large weather clock will translate the same as smartspace val useScaleOnly = - useAltAod && keyguardClockViewModel.clockSize.value == ClockSize.LARGE + (!useAltAod) && keyguardClockViewModel.clockSize.value == ClockSize.LARGE val burnInY = MathUtils.lerp(0, burnIn.translationY, interpolated).toInt() val translationY = @@ -134,35 +135,12 @@ constructor( } else { max(params.topInset, params.minViewY + burnInY) - params.minViewY } - if (ComposeLockscreen.isEnabled) { - BurnInModel( - translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(), - translationY = translationY, - scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated), - scaleClockOnly = !useScaleOnly, - ) - } else { - if (useScaleOnly) { - BurnInModel( - translationX = 0, - translationY = 0, - scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated), - ) - } else { - // Ensure the desired translation doesn't encroach on the top inset - BurnInModel( - translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(), - translationY = translationY, - scale = - MathUtils.lerp( - /* start= */ burnIn.scale, - /* stop= */ 1f, - /* amount= */ 1f - interpolated, - ), - scaleClockOnly = true, - ) - } - } + BurnInModel( + translationX = MathUtils.lerp(0, burnIn.translationX, interpolated).toInt(), + translationY = translationY, + scale = MathUtils.lerp(burnIn.scale, 1f, 1f - interpolated), + scaleClockOnly = useScaleOnly + ) } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt index 87324a233cef..6f8389fc8b7c 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryBackgroundViewModel.kt @@ -117,7 +117,8 @@ constructor( KeyguardState.DOZING, KeyguardState.DREAMING, KeyguardState.PRIMARY_BOUNCER, - KeyguardState.AOD -> emit(0f) + KeyguardState.AOD, + KeyguardState.UNDEFINED -> emit(0f) KeyguardState.ALTERNATE_BOUNCER, KeyguardState.LOCKSCREEN -> emit(1f) } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt index 53b2697a53de..ae83c9e720a3 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryIconViewModel.kt @@ -148,10 +148,11 @@ constructor( KeyguardState.GLANCEABLE_HUB, KeyguardState.GONE, KeyguardState.OCCLUDED, - KeyguardState.DREAMING_LOCKSCREEN_HOSTED, -> 0f + KeyguardState.DREAMING_LOCKSCREEN_HOSTED, + KeyguardState.UNDEFINED, -> 0f KeyguardState.AOD, KeyguardState.ALTERNATE_BOUNCER, - KeyguardState.LOCKSCREEN -> 1f + KeyguardState.LOCKSCREEN, -> 1f } } val useBackgroundProtection: StateFlow<Boolean> = isUdfpsSupported diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt index 7468675c4bf8..a083c24e3d4d 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DreamingToGlanceableHubTransitionViewModel.kt @@ -21,6 +21,7 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import com.android.systemui.res.R import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -37,7 +38,7 @@ class DreamingToGlanceableHubTransitionViewModel constructor( animationFlow: KeyguardTransitionAnimationFlow, configurationInteractor: ConfigurationInteractor, -) { +) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( duration = TO_GLANCEABLE_HUB_DURATION, @@ -79,6 +80,15 @@ constructor( ) .map { step -> step != 0f } + override val deviceEntryParentViewAlpha: Flow<Float> = + transitionAnimation.sharedFlow( + startTime = 167.milliseconds, + duration = 167.milliseconds, + onStep = { it }, + onCancel = { 0f }, + onFinish = { 1f }, + ) + private companion object { val TO_GLANCEABLE_HUB_DURATION = 1.seconds } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt index 838c22b0da33..3716458079cd 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToDreamingTransitionViewModel.kt @@ -21,6 +21,7 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition import com.android.systemui.res.R import javax.inject.Inject import kotlin.time.Duration.Companion.milliseconds @@ -37,7 +38,7 @@ class GlanceableHubToDreamingTransitionViewModel constructor( animationFlow: KeyguardTransitionAnimationFlow, configurationInteractor: ConfigurationInteractor, -) { +) : DeviceEntryIconTransition { private val transitionAnimation = animationFlow.setup( @@ -78,6 +79,14 @@ constructor( ) .map { step -> step != 1f } + override val deviceEntryParentViewAlpha: Flow<Float> = + transitionAnimation.sharedFlow( + duration = 167.milliseconds, + onStep = { 1 - it }, + onCancel = { 1f }, + onFinish = { 0f }, + ) + private companion object { val FROM_GLANCEABLE_HUB_DURATION = 1.seconds } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModel.kt new file mode 100644 index 000000000000..300121facfd5 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/GlanceableHubToOccludedTransitionViewModel.kt @@ -0,0 +1,43 @@ +/* + * 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.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.FromGlanceableHubTransitionInteractor.Companion.TO_OCCLUDED_DURATION +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +@SysUISingleton +class GlanceableHubToOccludedTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, +) : DeviceEntryIconTransition { + + private val transitionAnimation = + animationFlow.setup( + duration = TO_OCCLUDED_DURATION, + from = KeyguardState.GLANCEABLE_HUB, + to = KeyguardState.OCCLUDED, + ) + + override val deviceEntryParentViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(0f) +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/MediaCarouselViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt index bf225633fa86..e68e465ed55a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/MediaCarouselViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardMediaViewModel.kt @@ -16,10 +16,10 @@ package com.android.systemui.keyguard.ui.viewmodel -import com.android.systemui.media.controls.domain.pipeline.MediaDataManager +import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow -class MediaCarouselViewModel @Inject constructor(private val mediaDataManager: MediaDataManager) { - val isMediaVisible: Boolean - get() = mediaDataManager.hasActiveMediaOrRecommendation() +class KeyguardMediaViewModel @Inject constructor(mediaCarouselInteractor: MediaCarouselInteractor) { + val isMediaVisible: StateFlow<Boolean> = mediaCarouselInteractor.hasActiveMediaOrRecommendation } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt index d8b50133949d..02e48fc5a09b 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt @@ -28,6 +28,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor import com.android.systemui.scene.shared.model.Scenes +import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel @@ -89,10 +90,15 @@ constructor( shadeMode: ShadeMode, ): Map<UserAction, UserActionResult> { val shadeSceneKey = - if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade + UserActionResult( + toScene = + if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade, + transitionKey = ToSplitShade.takeIf { shadeMode is ShadeMode.Split }, + ) val quickSettingsIfSingleShade = - if (shadeMode is ShadeMode.Single) Scenes.QuickSettings else shadeSceneKey + if (shadeMode is ShadeMode.Single) UserActionResult(Scenes.QuickSettings) + else shadeSceneKey return mapOf( Swipe.Left to UserActionResult(Scenes.Communal).takeIf { isCommunalAvailable }, @@ -103,7 +109,7 @@ constructor( swipeDownFromTop(pointerCount = 2) to // TODO(b/338577208): Remove 'Dual' once we add Dual Shade invocation zones. if (shadeMode is ShadeMode.Dual) { - Scenes.QuickSettingsShade + UserActionResult(Scenes.QuickSettingsShade) } else { quickSettingsIfSingleShade }, diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModel.kt new file mode 100644 index 000000000000..73a4a9d4d2bb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/OccludedToGlanceableHubTransitionViewModel.kt @@ -0,0 +1,43 @@ +/* + * 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.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.keyguard.domain.interactor.FromOccludedTransitionInteractor.Companion.TO_GLANCEABLE_HUB_DURATION +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.ui.KeyguardTransitionAnimationFlow +import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow + +@SysUISingleton +class OccludedToGlanceableHubTransitionViewModel +@Inject +constructor( + animationFlow: KeyguardTransitionAnimationFlow, +) : DeviceEntryIconTransition { + + private val transitionAnimation = + animationFlow.setup( + duration = TO_GLANCEABLE_HUB_DURATION, + from = KeyguardState.OCCLUDED, + to = KeyguardState.GLANCEABLE_HUB, + ) + + override val deviceEntryParentViewAlpha: Flow<Float> = + transitionAnimation.immediatelyTransitionTo(1f) +} diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt index 9719c029574f..0c70f10bba21 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/data/repository/MediaFilterRepository.kt @@ -107,14 +107,11 @@ constructor( .thenByDescending { it.updateTime } .thenByDescending { it.notificationKey } - private val _sortedMedia: MutableStateFlow<TreeMap<MediaSortKeyModel, MediaCommonModel>> = - MutableStateFlow(TreeMap<MediaSortKeyModel, MediaCommonModel>(comparator)) - val sortedMedia: StateFlow<Map<MediaSortKeyModel, MediaCommonModel>> = - _sortedMedia.asStateFlow() - - private val _isMediaFromRec: MutableStateFlow<Boolean> = MutableStateFlow(false) - val isMediaFromRec: StateFlow<Boolean> = _isMediaFromRec.asStateFlow() + private val _currentMedia: MutableStateFlow<List<MediaCommonModel>> = + MutableStateFlow(mutableListOf()) + val currentMedia = _currentMedia.asStateFlow() + private var sortedMedia = TreeMap<MediaSortKeyModel, MediaCommonModel>(comparator) private var mediaFromRecPackageName: String? = null private var locale: Locale = applicationContext.resources.configuration.locales.get(0) @@ -186,7 +183,7 @@ constructor( fun addMediaDataLoadingState(mediaDataLoadingModel: MediaDataLoadingModel) { val sortedMap = TreeMap<MediaSortKeyModel, MediaCommonModel>(comparator) sortedMap.putAll( - _sortedMedia.value.filter { (_, commonModel) -> + sortedMedia.filter { (_, commonModel) -> commonModel !is MediaCommonModel.MediaControl || commonModel.mediaLoadedModel.instanceId != mediaDataLoadingModel.instanceId } @@ -207,18 +204,52 @@ constructor( ) if (mediaDataLoadingModel is MediaDataLoadingModel.Loaded) { - val isMediaFromRec = isMediaFromRec(it) - - _isMediaFromRec.value = isMediaFromRec - if (isMediaFromRec) { - mediaFromRecPackageName = null + val newCommonModel = + MediaCommonModel.MediaControl( + mediaDataLoadingModel, + canBeRemoved(it), + isMediaFromRec(it) + ) + sortedMap[sortKey] = newCommonModel + + // On Addition or tapping on recommendations, we should show the new order of media. + if (mediaFromRecPackageName == it.packageName) { + if (it.isPlaying == true) { + mediaFromRecPackageName = null + _currentMedia.value = sortedMap.values.toList() + } + } else if (sortedMap.size > sortedMedia.size) { + _currentMedia.value = sortedMap.values.toList() + } else if (sortedMap.size == sortedMedia.size) { + // When loading an update for an existing media control. + val currentList = + mutableListOf<MediaCommonModel>().apply { addAll(_currentMedia.value) } + currentList.forEachIndexed { index, mediaCommonModel -> + if ( + mediaCommonModel is MediaCommonModel.MediaControl && + mediaCommonModel.mediaLoadedModel.instanceId == + mediaDataLoadingModel.instanceId && + mediaCommonModel != newCommonModel + ) { + // Update media model if changed. + currentList[index] = newCommonModel + } + } + _currentMedia.value = currentList } - sortedMap[sortKey] = - MediaCommonModel.MediaControl(mediaDataLoadingModel, canBeRemoved(it)) } } - _sortedMedia.value = sortedMap + sortedMedia = sortedMap + + // On removal we want to keep the order being shown to user. + if (mediaDataLoadingModel is MediaDataLoadingModel.Removed) { + _currentMedia.value = + _currentMedia.value.filter { commonModel -> + commonModel !is MediaCommonModel.MediaControl || + mediaDataLoadingModel.instanceId != commonModel.mediaLoadedModel.instanceId + } + } } fun setRecommendationsLoadingState(smartspaceMediaLoadingModel: SmartspaceMediaLoadingModel) { @@ -229,7 +260,7 @@ constructor( } val sortedMap = TreeMap<MediaSortKeyModel, MediaCommonModel>(comparator) sortedMap.putAll( - _sortedMedia.value.filter { (_, commonModel) -> + sortedMedia.filter { (_, commonModel) -> commonModel !is MediaCommonModel.MediaRecommendations } ) @@ -240,11 +271,25 @@ constructor( isPlaying = false, active = _smartspaceMediaData.value.isActive, ) - if (smartspaceMediaLoadingModel is SmartspaceMediaLoadingModel.Loaded) { - sortedMap[sortKey] = MediaCommonModel.MediaRecommendations(smartspaceMediaLoadingModel) + when (smartspaceMediaLoadingModel) { + is SmartspaceMediaLoadingModel.Loaded -> + sortedMap[sortKey] = + MediaCommonModel.MediaRecommendations(smartspaceMediaLoadingModel) + is SmartspaceMediaLoadingModel.Removed -> + _currentMedia.value = + _currentMedia.value.filter { commonModel -> + commonModel !is MediaCommonModel.MediaRecommendations + } } - _sortedMedia.value = sortedMap + if (sortedMap.size > sortedMedia.size) { + _currentMedia.value = sortedMap.values.toList() + } + sortedMedia = sortedMap + } + + fun setOrderedMedia() { + _currentMedia.value = sortedMedia.values.toList() } fun setMediaFromRecPackageName(packageName: String) { diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImpl.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImpl.kt index c02478b02ec2..96ef7d250012 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImpl.kt @@ -206,11 +206,11 @@ constructor( listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable) } } - override fun onMediaDataRemoved(key: String) { + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { allEntries.remove(key) userEntries.remove(key)?.let { // Only notify listeners if something actually changed - listeners.forEach { it.onMediaDataRemoved(key) } + listeners.forEach { it.onMediaDataRemoved(key, userInitiated) } } } @@ -246,7 +246,7 @@ constructor( // Only remove media when the profile is unavailable. if (DEBUG) Log.d(TAG, "Removing $key after profile change") userEntries.remove(key, data) - listeners.forEach { listener -> listener.onMediaDataRemoved(key) } + listeners.forEach { listener -> listener.onMediaDataRemoved(key, false) } } } } @@ -261,7 +261,7 @@ constructor( userEntries.clear() keyCopy.forEach { if (DEBUG) Log.d(TAG, "Removing $it after user change") - listenersCopy.forEach { listener -> listener.onMediaDataRemoved(it) } + listenersCopy.forEach { listener -> listener.onMediaDataRemoved(it, false) } } allEntries.forEach { (key, data) -> diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt index 3a83115642bc..143d66b69f57 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImpl.kt @@ -545,8 +545,8 @@ class LegacyMediaDataManagerImpl( * External listeners registered with [addListener] will be notified after the event propagates * through the internal listener pipeline. */ - private fun notifyMediaDataRemoved(key: String) { - internalListeners.forEach { it.onMediaDataRemoved(key) } + private fun notifyMediaDataRemoved(key: String, userInitiated: Boolean = false) { + internalListeners.forEach { it.onMediaDataRemoved(key, userInitiated) } } /** @@ -578,7 +578,7 @@ class LegacyMediaDataManagerImpl( if (it.active == !timedOut && !forceUpdate) { if (it.resumption) { if (DEBUG) Log.d(TAG, "timing out resume player $key") - dismissMediaData(key, 0L /* delay */) + dismissMediaData(key, delay = 0L, userInitiated = false) } return } @@ -627,17 +627,17 @@ class LegacyMediaDataManagerImpl( } } - private fun removeEntry(key: String, logEvent: Boolean = true) { + private fun removeEntry(key: String, logEvent: Boolean = true, userInitiated: Boolean = false) { mediaEntries.remove(key)?.let { if (logEvent) { logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId) } } - notifyMediaDataRemoved(key) + notifyMediaDataRemoved(key, userInitiated) } /** Dismiss a media entry. Returns false if the key was not found. */ - override fun dismissMediaData(key: String, delay: Long): Boolean { + override fun dismissMediaData(key: String, delay: Long, userInitiated: Boolean): Boolean { val existed = mediaEntries[key] != null backgroundExecutor.execute { mediaEntries[key]?.let { mediaData -> @@ -649,7 +649,10 @@ class LegacyMediaDataManagerImpl( } } } - foregroundExecutor.executeDelayed({ removeEntry(key) }, delay) + foregroundExecutor.executeDelayed( + { removeEntry(key = key, userInitiated = userInitiated) }, + delay + ) return existed } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatest.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatest.kt index ad70db5a3300..88910f944466 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatest.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatest.kt @@ -53,8 +53,8 @@ class MediaDataCombineLatest @Inject constructor() : listeners.toSet().forEach { it.onSmartspaceMediaDataLoaded(key, data) } } - override fun onMediaDataRemoved(key: String) { - remove(key) + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { + remove(key, userInitiated) } override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) { @@ -71,8 +71,8 @@ class MediaDataCombineLatest @Inject constructor() : } } - override fun onKeyRemoved(key: String) { - remove(key) + override fun onKeyRemoved(key: String, userInitiated: Boolean) { + remove(key, userInitiated) } /** @@ -92,10 +92,10 @@ class MediaDataCombineLatest @Inject constructor() : } } - private fun remove(key: String) { + private fun remove(key: String, userInitiated: Boolean) { entries.remove(key)?.let { val listenersCopy = listeners.toSet() - listenersCopy.forEach { it.onMediaDataRemoved(key) } + listenersCopy.forEach { it.onMediaDataRemoved(key, userInitiated) } } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt index 5432a189cf7c..8d19ce800cbe 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImpl.kt @@ -213,7 +213,7 @@ constructor( listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable) } } - override fun onMediaDataRemoved(key: String) { + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { mediaFilterRepository.removeMediaEntry(key)?.let { mediaData -> val instanceId = mediaData.instanceId mediaFilterRepository.removeSelectedUserMediaEntry(instanceId)?.let { @@ -221,7 +221,7 @@ constructor( MediaDataLoadingModel.Removed(instanceId) ) // Only notify listeners if something actually changed - listeners.forEach { it.onMediaDataRemoved(key) } + listeners.forEach { it.onMediaDataRemoved(key, userInitiated) } } } } @@ -270,7 +270,7 @@ constructor( mediaFilterRepository.addMediaDataLoadingState( MediaDataLoadingModel.Removed(data.instanceId) ) - listeners.forEach { listener -> listener.onMediaDataRemoved(key) } + listeners.forEach { listener -> listener.onMediaDataRemoved(key, false) } } } } @@ -288,7 +288,7 @@ constructor( MediaDataLoadingModel.Removed(instanceId) ) getKey(instanceId)?.let { - listenersCopy.forEach { listener -> listener.onMediaDataRemoved(it) } + listenersCopy.forEach { listener -> listener.onMediaDataRemoved(it, false) } } } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt index 2331aa2170ef..8099e593b33d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataManager.kt @@ -60,7 +60,7 @@ interface MediaDataManager { ) /** Dismiss a media entry. Returns false if the key was not found. */ - fun dismissMediaData(key: String, delay: Long): Boolean + fun dismissMediaData(key: String, delay: Long, userInitiated: Boolean): Boolean /** * Called whenever the recommendation has been expired or removed by the user. This will remove @@ -136,7 +136,7 @@ interface MediaDataManager { ) {} /** Called whenever a previously existing Media notification was removed. */ - override fun onMediaDataRemoved(key: String) {} + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) {} /** * Called whenever a previously existing Smartspace media data was removed. diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt index 1d7c0256b2ef..eed775242d1f 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessor.kt @@ -498,8 +498,8 @@ class MediaDataProcessor( * External listeners registered with [MediaCarouselInteractor.addListener] will be notified * after the event propagates through the internal listener pipeline. */ - private fun notifyMediaDataRemoved(key: String) { - internalListeners.forEach { it.onMediaDataRemoved(key) } + private fun notifyMediaDataRemoved(key: String, userInitiated: Boolean = false) { + internalListeners.forEach { it.onMediaDataRemoved(key, userInitiated) } } /** @@ -531,7 +531,7 @@ class MediaDataProcessor( if (it.active == !timedOut && !forceUpdate) { if (it.resumption) { if (DEBUG) Log.d(TAG, "timing out resume player $key") - dismissMediaData(key, 0L /* delay */) + dismissMediaData(key, delayMs = 0L, userInitiated = false) } return } @@ -580,17 +580,17 @@ class MediaDataProcessor( } } - private fun removeEntry(key: String, logEvent: Boolean = true) { + private fun removeEntry(key: String, logEvent: Boolean = true, userInitiated: Boolean = false) { mediaDataRepository.removeMediaEntry(key)?.let { if (logEvent) { logger.logMediaRemoved(it.appUid, it.packageName, it.instanceId) } } - notifyMediaDataRemoved(key) + notifyMediaDataRemoved(key, userInitiated) } /** Dismiss a media entry. Returns false if the key was not found. */ - fun dismissMediaData(key: String, delayMs: Long): Boolean { + fun dismissMediaData(key: String, delayMs: Long, userInitiated: Boolean): Boolean { val existed = mediaDataRepository.mediaEntries.value[key] != null backgroundExecutor.execute { mediaDataRepository.mediaEntries.value[key]?.let { mediaData -> @@ -602,16 +602,19 @@ class MediaDataProcessor( } } } - foregroundExecutor.executeDelayed({ removeEntry(key) }, delayMs) + foregroundExecutor.executeDelayed( + { removeEntry(key, userInitiated = userInitiated) }, + delayMs + ) return existed } /** Dismiss a media entry. Returns false if the corresponding key was not found. */ - fun dismissMediaData(instanceId: InstanceId, delayMs: Long): Boolean { + fun dismissMediaData(instanceId: InstanceId, delayMs: Long, userInitiated: Boolean): Boolean { val mediaEntries = mediaDataRepository.mediaEntries.value val filteredEntries = mediaEntries.filter { (_, data) -> data.instanceId == instanceId } return if (filteredEntries.isNotEmpty()) { - dismissMediaData(filteredEntries.keys.first(), delayMs) + dismissMediaData(filteredEntries.keys.first(), delayMs, userInitiated) } else { false } @@ -1579,7 +1582,7 @@ class MediaDataProcessor( ) {} /** Called whenever a previously existing Media notification was removed. */ - fun onMediaDataRemoved(key: String) {} + fun onMediaDataRemoved(key: String, userInitiated: Boolean) {} /** * Called whenever a previously existing Smartspace media data was removed. diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt index 0e2814b3d91e..043fbfaa8a23 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManager.kt @@ -111,10 +111,10 @@ constructor( } } - override fun onMediaDataRemoved(key: String) { + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { val token = entries.remove(key) token?.stop() - token?.let { listeners.forEach { it.onKeyRemoved(key) } } + token?.let { listeners.forEach { it.onKeyRemoved(key, userInitiated) } } } fun dump(pw: PrintWriter) { @@ -136,7 +136,7 @@ constructor( /** Called when the route has changed for a given notification. */ fun onMediaDeviceChanged(key: String, oldKey: String?, data: MediaDeviceData?) /** Called when the notification was removed. */ - fun onKeyRemoved(key: String) + fun onKeyRemoved(key: String, userInitiated: Boolean) } private inner class Entry( diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilter.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilter.kt index b2a8f2e71cc6..b178d84c5d18 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilter.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilter.kt @@ -137,7 +137,7 @@ constructor( // farther and dismiss the media data so that media controls for the local session // don't hang around while casting. if (!keyedTokens.get(key)!!.contains(TokenId(remote.sessionToken))) { - dispatchMediaDataRemoved(key) + dispatchMediaDataRemoved(key, userInitiated = false) } } } @@ -151,11 +151,11 @@ constructor( backgroundExecutor.execute { dispatchSmartspaceMediaDataLoaded(key, data) } } - override fun onMediaDataRemoved(key: String) { + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { // Queue on background thread to ensure ordering of loaded and removed events is maintained. backgroundExecutor.execute { keyedTokens.remove(key) - dispatchMediaDataRemoved(key) + dispatchMediaDataRemoved(key, userInitiated) } } @@ -174,8 +174,10 @@ constructor( } } - private fun dispatchMediaDataRemoved(key: String) { - foregroundExecutor.execute { listeners.toSet().forEach { it.onMediaDataRemoved(key) } } + private fun dispatchMediaDataRemoved(key: String, userInitiated: Boolean) { + foregroundExecutor.execute { + listeners.toSet().forEach { it.onMediaDataRemoved(key, userInitiated) } + } } private fun dispatchSmartspaceMediaDataLoaded(key: String, info: SmartspaceMediaData) { diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt index 29f396700831..fc319036d67e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListener.kt @@ -169,7 +169,7 @@ constructor( mediaListeners[key] = PlaybackStateListener(key, data) } - override fun onMediaDataRemoved(key: String) { + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { mediaListeners.remove(key)?.destroy() } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt index 33c0b195bf50..9e6230012760 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaCarouselInteractor.kt @@ -63,7 +63,7 @@ constructor( private val mediaDeviceManager: MediaDeviceManager, private val mediaDataCombineLatest: MediaDataCombineLatest, private val mediaDataFilter: MediaDataFilterImpl, - mediaFilterRepository: MediaFilterRepository, + private val mediaFilterRepository: MediaFilterRepository, private val mediaFlags: MediaFlags, ) : MediaDataManager, CoreStartable { @@ -123,18 +123,8 @@ constructor( initialValue = false, ) - /** The most recent sorted set for user media instances */ - val sortedMedia: StateFlow<List<MediaCommonModel>> = - mediaFilterRepository.sortedMedia - .mapLatest { it.values.toList() } - .stateIn( - scope = applicationScope, - started = SharingStarted.WhileSubscribed(), - initialValue = emptyList(), - ) - - /** Whether the current change in media was done by clicking on a recommendation */ - val isMediaFromRec: StateFlow<Boolean> = mediaFilterRepository.isMediaFromRec + /** The current list for user media instances */ + val currentMedia: StateFlow<List<MediaCommonModel>> = mediaFilterRepository.currentMedia override fun start() { if (!mediaFlags.isMediaControlsRefactorEnabled()) { @@ -215,12 +205,12 @@ constructor( ) } - override fun dismissMediaData(key: String, delay: Long): Boolean { - return mediaDataProcessor.dismissMediaData(key, delay) + override fun dismissMediaData(key: String, delay: Long, userInitiated: Boolean): Boolean { + return mediaDataProcessor.dismissMediaData(key, delay, userInitiated) } fun removeMediaControl(instanceId: InstanceId, delay: Long) { - mediaDataProcessor.dismissMediaData(instanceId, delay) + mediaDataProcessor.dismissMediaData(instanceId, delay, userInitiated = false) } override fun dismissSmartspaceRecommendation(key: String, delay: Long) { @@ -251,6 +241,10 @@ constructor( override fun isRecommendationActive() = mediaDataRepository.smartspaceMediaData.value.isActive + fun reorderMedia() { + mediaFilterRepository.setOrderedMedia() + } + /** Add a listener for internal events. */ private fun addInternalListener(listener: MediaDataManager.Listener) = mediaDataProcessor.addInternalListener(listener) diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt index 9f2d132fc7a9..d1fee903e6f5 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaControlInteractor.kt @@ -90,7 +90,8 @@ constructor( instanceId: InstanceId, delayMs: Long ): Boolean { - val dismissed = mediaDataProcessor.dismissMediaData(instanceId, delayMs) + val dismissed = + mediaDataProcessor.dismissMediaData(instanceId, delayMs, userInitiated = true) if (!dismissed) { Log.w( TAG, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaCommonModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaCommonModel.kt index 23860bb9868c..56cc618eb61c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaCommonModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/shared/model/MediaCommonModel.kt @@ -21,6 +21,7 @@ sealed class MediaCommonModel { data class MediaControl( val mediaLoadedModel: MediaDataLoadingModel.Loaded, val canBeRemoved: Boolean = false, + val isMediaFromRec: Boolean = false, ) : MediaCommonModel() data class MediaRecommendations(val recsLoadingModel: SmartspaceMediaLoadingModel) : diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt index 0478178e71d6..b07253402645 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselController.kt @@ -193,6 +193,7 @@ constructor( private val mediaContent: ViewGroup @VisibleForTesting var pageIndicator: PageIndicator private var needsReordering: Boolean = false + private var isUserInitiatedRemovalQueued: Boolean = false private var keysNeedRemoval = mutableSetOf<String>() var shouldScrollToKey: Boolean = false private var isRtl: Boolean = false @@ -359,6 +360,8 @@ constructor( ) keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback) mediaCarousel.repeatWhenAttached { + mediaCarouselViewModel.onAttached() + mediaCarouselScrollHandler.scrollToStart() repeatOnLifecycle(Lifecycle.State.STARTED) { listenForAnyStateToGoneKeyguardTransition(this) listenForAnyStateToLockscreenTransition(this) @@ -383,12 +386,15 @@ constructor( reorderAllPlayers(previousVisiblePlayerKey = null) } - keysNeedRemoval.forEach { removePlayer(it) } + keysNeedRemoval.forEach { + removePlayer(it, userInitiated = isUserInitiatedRemovalQueued) + } if (keysNeedRemoval.size > 0) { // Carousel visibility may need to be updated after late removals updateHostVisibility() } keysNeedRemoval.clear() + isUserInitiatedRemovalQueued = false // Update user visibility so that no extra impression will be logged when // activeMediaIndex resets to 0 @@ -472,18 +478,18 @@ constructor( val canRemove = data.isPlaying?.let { !it } ?: data.isClearable && !data.active if (canRemove && !Utils.useMediaResumption(context)) { - // This view isn't playing, let's remove this! This happens e.g. when - // dismissing/timing out a view. We still have the data around because - // resumption could be on, but we should save the resources and release - // this. + // This media control is both paused and timed out, and the resumption + // setting is off - let's remove it if (isReorderingAllowed) { - onMediaDataRemoved(key) + onMediaDataRemoved(key, userInitiated = MediaPlayerData.isSwipedAway) } else { + isUserInitiatedRemovalQueued = MediaPlayerData.isSwipedAway keysNeedRemoval.add(key) } } else { keysNeedRemoval.remove(key) } + MediaPlayerData.isSwipedAway = false } override fun onSmartspaceMediaDataLoaded( @@ -563,11 +569,12 @@ constructor( addSmartspaceMediaRecommendations(key, data, shouldPrioritize) } } + MediaPlayerData.isSwipedAway = false } - override fun onMediaDataRemoved(key: String) { - debugLogger.logMediaRemoved(key) - removePlayer(key) + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { + debugLogger.logMediaRemoved(key, userInitiated) + removePlayer(key, userInitiated = userInitiated) } override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) { @@ -734,6 +741,14 @@ constructor( viewController.setListening(mediaCarouselScrollHandler.visibleToUser && currentlyExpanded) updateViewControllerToState(viewController, noAnimation = true) updatePageIndicator() + if ( + commonViewModel is MediaCommonViewModel.MediaControl && commonViewModel.isMediaFromRec + ) { + mediaCarouselScrollHandler.scrollToPlayer( + mediaCarouselScrollHandler.visibleMediaIndex, + destIndex = 0 + ) + } mediaCarouselScrollHandler.onPlayersChanged() mediaFrame.requiresRemeasuring = true commonViewModel.onAdded(commonViewModel) @@ -1023,7 +1038,8 @@ constructor( fun removePlayer( key: String, dismissMediaData: Boolean = true, - dismissRecommendation: Boolean = true + dismissRecommendation: Boolean = true, + userInitiated: Boolean = false, ): MediaControlPanel? { if (key == MediaPlayerData.smartspaceMediaKey()) { MediaPlayerData.smartspaceMediaData?.let { @@ -1042,7 +1058,7 @@ constructor( if (dismissMediaData) { // Inform the media manager of a potentially late dismissal - mediaManager.dismissMediaData(key, delay = 0L) + mediaManager.dismissMediaData(key, delay = 0L, userInitiated = userInitiated) } if (dismissRecommendation) { // Inform the media manager of a potentially late dismissal @@ -1502,7 +1518,8 @@ constructor( } } - private fun onSwipeToDismiss() { + @VisibleForTesting + fun onSwipeToDismiss() { if (mediaFlags.isMediaControlsRefactorEnabled()) { mediaCarouselViewModel.onSwipeToDismiss() return @@ -1521,6 +1538,7 @@ constructor( it.mIsImpressed = false } } + MediaPlayerData.isSwipedAway = true logger.logSwipeDismiss() mediaManager.onSwipeToDismiss() } @@ -1547,6 +1565,7 @@ constructor( "state: ${desiredHostState?.expansion}, " + "only active ${desiredHostState?.showsOnlyActiveMedia}" ) + println("isSwipedAway: ${MediaPlayerData.isSwipedAway}") } } } @@ -1585,7 +1604,7 @@ internal object MediaPlayerData { val data: MediaData, val key: String, val updateTime: Long = 0, - val isSsReactivated: Boolean = false + val isSsReactivated: Boolean = false, ) private val comparator = @@ -1610,6 +1629,9 @@ internal object MediaPlayerData { // A map that tracks order of visible media players before they get reordered. private val visibleMediaPlayers = LinkedHashMap<String, MediaSortKey>() + // Whether the user swiped away the carousel since its last update + internal var isSwipedAway: Boolean = false + fun addMediaPlayer( key: String, data: MediaData, diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt index ebf1c6a10703..1be25a74dbea 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt @@ -53,8 +53,16 @@ constructor(@MediaCarouselControllerLog private val buffer: LogBuffer) { { "add player $str1, active: $bool1" } ) - fun logMediaRemoved(key: String) = - buffer.log(TAG, LogLevel.DEBUG, { str1 = key }, { "removing player $str1" }) + fun logMediaRemoved(key: String, userInitiated: Boolean) = + buffer.log( + TAG, + LogLevel.DEBUG, + { + str1 = key + bool1 = userInitiated + }, + { "removing player $str1, by user $bool1" } + ) fun logRecommendationLoaded(key: String, isActive: Boolean) = buffer.log( diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java index e6c785ef41f0..0bc3c43993dd 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java @@ -786,10 +786,11 @@ public class MediaControlPanel { if (mKey != null) { closeGuts(); if (!mMediaDataManagerLazy.get().dismissMediaData(mKey, - MediaViewController.GUTS_ANIMATION_DURATION + 100)) { + /* delay */ MediaViewController.GUTS_ANIMATION_DURATION + 100, + /* userInitiated */ true)) { Log.w(TAG, "Manager failed to dismiss media " + mKey); // Remove directly from carousel so user isn't stuck with defunct controls - mMediaCarouselController.removePlayer(mKey, false, false); + mMediaCarouselController.removePlayer(mKey, false, false, true); } } else { Log.w(TAG, "Dismiss media with null notification. Token uid=" diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt index eca76b603b1a..91050c8bfab3 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/MediaHost.kt @@ -105,7 +105,7 @@ class MediaHost( updateViewVisibility() } - override fun onMediaDataRemoved(key: String) { + override fun onMediaDataRemoved(key: String, userInitiated: Boolean) { updateViewVisibility() } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt index 96a8239a2c60..fd5f44594ae8 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt @@ -26,21 +26,15 @@ import com.android.systemui.media.controls.domain.pipeline.interactor.factory.Me import com.android.systemui.media.controls.shared.model.MediaCommonModel import com.android.systemui.media.controls.util.MediaFlags import com.android.systemui.media.controls.util.MediaUiEventLogger -import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider import com.android.systemui.util.Utils -import com.android.systemui.util.kotlin.pairwiseBy -import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import java.util.concurrent.Executor import javax.inject.Inject import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn /** Models UI state and handles user inputs for media carousel */ @@ -60,45 +54,26 @@ constructor( private val mediaFlags: MediaFlags, ) { - @OptIn(ExperimentalCoroutinesApi::class) val mediaItems: StateFlow<List<MediaCommonViewModel>> = - conflatedCallbackFlow { - val listener = OnReorderingAllowedListener { trySend(Unit) } - visualStabilityProvider.addPersistentReorderingAllowedListener(listener) - trySend(Unit) - awaitClose { visualStabilityProvider.removeReorderingAllowedListener(listener) } - } - .flatMapLatest { - combine(interactor.isMediaFromRec, interactor.sortedMedia) { - isRecsToMedia, - sortedItems -> - buildList { - shouldReorder = isRecsToMedia - val reorderAllowed = isReorderingAllowed() - sortedItems.forEach { commonModel -> - if (!reorderAllowed || !modelsPendingRemoval.contains(commonModel)) { - when (commonModel) { - is MediaCommonModel.MediaControl -> - add(toViewModel(commonModel)) - is MediaCommonModel.MediaRecommendations -> - add(toViewModel(commonModel)) - } + interactor.currentMedia + .map { sortedItems -> + buildList { + sortedItems.forEach { commonModel -> + // When view is started we should make sure to clean models that are pending + // removal. + // This action should only be triggered once. + if (!isAttached || !modelsPendingRemoval.contains(commonModel)) { + when (commonModel) { + is MediaCommonModel.MediaControl -> add(toViewModel(commonModel)) + is MediaCommonModel.MediaRecommendations -> + add(toViewModel(commonModel)) } } - if (reorderAllowed) { - modelsPendingRemoval.clear() - } } - } - } - .pairwiseBy { old, new -> - // This condition can only happen when view is attached. So the old emit is of the - // most recent list updated. - // If the old list is empty, it is okay to emit the new ordered list. - if (isReorderingAllowed() || shouldReorder || old.isEmpty()) { - new - } else { - old + if (isAttached) { + modelsPendingRemoval.clear() + } + isAttached = false } } .stateIn( @@ -114,13 +89,18 @@ constructor( private var modelsPendingRemoval: MutableSet<MediaCommonModel> = mutableSetOf() - private var shouldReorder = true + private var isAttached = false fun onSwipeToDismiss() { logger.logSwipeDismiss() interactor.onSwipeToDismiss() } + fun onAttached() { + isAttached = true + interactor.reorderMedia() + } + private fun toViewModel( commonModel: MediaCommonModel.MediaControl ): MediaCommonViewModel.MediaControl { @@ -138,6 +118,7 @@ constructor( mediaControlByInstanceId.remove(instanceId) }, onUpdated = { onMediaControlAddedOrUpdated(it, commonModel) }, + isMediaFromRec = commonModel.isMediaFromRec ) .also { mediaControlByInstanceId[instanceId] = it } } diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt index aeaa82ed7244..a96d75c9ed30 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt @@ -32,6 +32,7 @@ sealed class MediaCommonViewModel { override val onAdded: (MediaCommonViewModel) -> Unit, override val onRemoved: (Boolean) -> Unit, override val onUpdated: (MediaCommonViewModel) -> Unit, + val isMediaFromRec: Boolean = false, ) : MediaCommonViewModel() data class MediaRecommendations( diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java index 88a5f78e407d..061e7ecfa4a3 100644 --- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java +++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java @@ -48,7 +48,7 @@ public class MediaDreamSentinel implements CoreStartable { } @Override - public void onMediaDataRemoved(@NonNull String key) { + public void onMediaDataRemoved(@NonNull String key, boolean userInitiated) { final boolean hasActiveMedia = mMediaDataManager.hasActiveMedia(); if (DEBUG) { Log.d(TAG, "onMediaDataRemoved(" + key + "), mAdded=" + mAdded + ", hasActiveMedia=" diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt index 89e4760615f0..a144dc2fc998 100644 --- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt +++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt @@ -29,6 +29,7 @@ import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICA import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED +import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags import dagger.Lazy import javax.inject.Inject @@ -48,7 +49,7 @@ constructor( * Returns an override value for the given [flag] or `null` if the scene framework isn't enabled * or if the flag value doesn't need to be overridden. */ - fun flagValueOverride(flag: Int): Boolean? { + fun flagValueOverride(@SystemUiStateFlags flag: Long): Boolean? { if (!SceneContainerFlag.isEnabled) { return null } @@ -79,7 +80,7 @@ constructor( * to be overridden by the scene framework. */ val EvaluatorByFlag = - mapOf<Int, (SceneContainerPluginState) -> Boolean>( + mapOf<Long, (SceneContainerPluginState) -> Boolean>( SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE to { it.scene != Scenes.Gone }, SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED to { diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java index 2dd2327e5387..481b4761ccd9 100644 --- a/packages/SystemUI/src/com/android/systemui/model/SysUiState.java +++ b/packages/SystemUI/src/com/android/systemui/model/SysUiState.java @@ -23,6 +23,7 @@ import com.android.systemui.Dumpable; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; import dalvik.annotation.optimization.NeverCompile; @@ -42,10 +43,10 @@ public class SysUiState implements Dumpable { private final DisplayTracker mDisplayTracker; private final SceneContainerPlugin mSceneContainerPlugin; - private @QuickStepContract.SystemUiStateFlags int mFlags; + private @SystemUiStateFlags long mFlags; private final List<SysUiStateCallback> mCallbacks = new ArrayList<>(); - private int mFlagsToSet = 0; - private int mFlagsToClear = 0; + private long mFlagsToSet = 0; + private long mFlagsToClear = 0; public SysUiState(DisplayTracker displayTracker, SceneContainerPlugin sceneContainerPlugin) { mDisplayTracker = displayTracker; @@ -67,12 +68,13 @@ public class SysUiState implements Dumpable { } /** Returns the current sysui state flags. */ - public int getFlags() { + @SystemUiStateFlags + public long getFlags() { return mFlags; } /** Methods to this call can be chained together before calling {@link #commitUpdate(int)}. */ - public SysUiState setFlag(int flag, boolean enabled) { + public SysUiState setFlag(@SystemUiStateFlags long flag, boolean enabled) { final Boolean overrideOrNull = mSceneContainerPlugin.flagValueOverride(flag); if (overrideOrNull != null && enabled != overrideOrNull) { if (DEBUG) { @@ -91,7 +93,7 @@ public class SysUiState implements Dumpable { return this; } - /** Call to save all the flags updated from {@link #setFlag(int, boolean)}. */ + /** Call to save all the flags updated from {@link #setFlag(long, boolean)}. */ public void commitUpdate(int displayId) { updateFlags(displayId); mFlagsToSet = 0; @@ -105,14 +107,14 @@ public class SysUiState implements Dumpable { return; } - int newState = mFlags; + long newState = mFlags; newState |= mFlagsToSet; newState &= ~mFlagsToClear; notifyAndSetSystemUiStateChanged(newState, mFlags); } /** Notify all those who are registered that the state has changed. */ - private void notifyAndSetSystemUiStateChanged(int newFlags, int oldFlags) { + private void notifyAndSetSystemUiStateChanged(long newFlags, long oldFlags) { if (DEBUG) { Log.d(TAG, "SysUiState changed: old=" + oldFlags + " new=" + newFlags); } @@ -137,7 +139,7 @@ public class SysUiState implements Dumpable { /** Callback to be notified whenever system UI state flags are changed. */ public interface SysUiStateCallback{ /** To be called when any SysUiStateFlag gets updated */ - void onSystemUiStateChanged(@QuickStepContract.SystemUiStateFlags int sysUiFlags); + void onSystemUiStateChanged(@SystemUiStateFlags long sysUiFlags); } } diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiStateExt.kt b/packages/SystemUI/src/com/android/systemui/model/SysUiStateExt.kt index 5c4915689f22..1e18f24c9e65 100644 --- a/packages/SystemUI/src/com/android/systemui/model/SysUiStateExt.kt +++ b/packages/SystemUI/src/com/android/systemui/model/SysUiStateExt.kt @@ -40,7 +40,7 @@ import com.android.systemui.dagger.qualifiers.DisplayId */ fun SysUiState.updateFlags( @DisplayId displayId: Int, - vararg flagValuePairs: Pair<Int, Boolean>, + vararg flagValuePairs: Pair<Long, Boolean>, ) { flagValuePairs.forEach { (flag, enabled) -> setFlag(flag, enabled) } commitUpdate(displayId) diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java index a6b6d61b464b..80c43796a55b 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java @@ -128,7 +128,7 @@ public final class NavBarHelper implements private boolean mLongPressHomeEnabled; private boolean mAssistantTouchGestureEnabled; private int mNavBarMode; - private int mA11yButtonState; + private long mA11yButtonState; private int mRotationWatcherRotation; private boolean mTogglingNavbarTaskbar; private boolean mWallpaperVisible; @@ -374,7 +374,7 @@ public final class NavBarHelper implements * {@link Secure#ACCESSIBILITY_BUTTON_MODE_GESTURE}, otherwise it is reset to 0. */ private void updateA11yState() { - final int prevState = mA11yButtonState; + final long prevState = mA11yButtonState; final boolean clickable; final boolean longClickable; if (mAccessibilityButtonModeObserver.getCurrentAccessibilityButtonMode() @@ -431,7 +431,7 @@ public final class NavBarHelper implements * 48 = the combination of {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_CLICKABLE} and * {@link QuickStepContract#SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE} */ - public int getA11yButtonState() { + public long getA11yButtonState() { return mA11yButtonState; } diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java index 906ebad5dd8d..0e819c2b0a4f 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java @@ -1602,7 +1602,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements void updateAccessibilityStateFlags() { mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled(); if (mView != null) { - int a11yFlags = mNavBarHelper.getA11yButtonState(); + long a11yFlags = mNavBarHelper.getA11yButtonState(); boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0; boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0; mView.setAccessibilityButtonState(clickable, longClickable); @@ -1611,7 +1611,7 @@ public class NavigationBar extends ViewController<NavigationBarView> implements } public void updateSystemUiStateFlags() { - int a11yFlags = mNavBarHelper.getA11yButtonState(); + long a11yFlags = mNavBarHelper.getA11yButtonState(); boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0; boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0; diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java index f67973bcd70e..b360af098fa0 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java @@ -298,7 +298,7 @@ public class TaskbarDelegate implements CommandQueue.Callbacks, } private void updateSysuiFlags() { - int a11yFlags = mNavBarHelper.getA11yButtonState(); + long a11yFlags = mNavBarHelper.getA11yButtonState(); boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0; boolean longClickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0; diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java index 295b2938bf54..94870853f1be 100644 --- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java @@ -84,6 +84,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputChannelCompat; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; import com.android.systemui.shared.system.SysUiStatsLog; import com.android.systemui.shared.system.TaskStackChangeListener; import com.android.systemui.shared.system.TaskStackChangeListeners; @@ -270,7 +271,8 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack private BackAnimation mBackAnimation; private int mLeftInset; private int mRightInset; - private int mSysUiFlags; + @SystemUiStateFlags + private long mSysUiFlags; // For Tf-Lite model. private BackGestureTfClassifierProvider mBackGestureTfClassifierProvider; @@ -334,7 +336,7 @@ public class EdgeBackGestureHandler implements PluginListener<NavigationEdgeBack private final SysUiState.SysUiStateCallback mSysUiStateCallback = new SysUiState.SysUiStateCallback() { @Override - public void onSystemUiStateChanged(int sysUiFlags) { + public void onSystemUiStateChanged(@SystemUiStateFlags long sysUiFlags) { mSysUiFlags = sysUiFlags; } }; diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java index 2a726c2835d9..24b7a011f093 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -19,6 +19,8 @@ import static android.os.PowerWhitelistManager.REASON_TILE_ONCLICK; import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI; import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PENDING_INTENT; +import static com.android.systemui.Flags.qsCustomTileClickGuaranteedBugFix; + import android.app.ActivityManager; import android.app.compat.CompatChanges; import android.content.BroadcastReceiver; @@ -88,6 +90,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements private static final int MSG_ON_REMOVED = 1; private static final int MSG_ON_CLICK = 2; private static final int MSG_ON_UNLOCK_COMPLETE = 3; + private static final int MSG_ON_STOP_LISTENING = 4; // Bind retry control. private static final int MAX_BIND_RETRIES = 5; @@ -368,6 +371,16 @@ public class TileLifecycleManager extends BroadcastReceiver implements onUnlockComplete(); } } + if (qsCustomTileClickGuaranteedBugFix()) { + if (queue.contains(MSG_ON_STOP_LISTENING)) { + if (mDebug) Log.d(TAG, "Handling pending onStopListening " + getComponent()); + if (mListening) { + onStopListening(); + } else { + Log.w(TAG, "Trying to stop listening when not listening " + getComponent()); + } + } + } if (queue.contains(MSG_ON_REMOVED)) { if (mDebug) Log.d(TAG, "Handling pending onRemoved " + getComponent()); if (mListening) { @@ -586,10 +599,15 @@ public class TileLifecycleManager extends BroadcastReceiver implements @Override public void onStopListening() { - if (mDebug) Log.d(TAG, "onStopListening " + getComponent()); - mListening = false; - if (isNotNullAndFailedAction(mOptionalWrapper, QSTileServiceWrapper::onStopListening)) { - handleDeath(); + if (qsCustomTileClickGuaranteedBugFix() && hasPendingClick()) { + Log.d(TAG, "Enqueue stop listening"); + queueMessage(MSG_ON_STOP_LISTENING); + } else { + if (mDebug) Log.d(TAG, "onStopListening " + getComponent()); + mListening = false; + if (isNotNullAndFailedAction(mOptionalWrapper, QSTileServiceWrapper::onStopListening)) { + handleDeath(); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java index f8bf0a684506..6bc5095ed1ea 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java @@ -15,6 +15,8 @@ */ package com.android.systemui.qs.external; +import static com.android.systemui.Flags.qsCustomTileClickGuaranteedBugFix; + import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -37,6 +39,7 @@ import com.android.systemui.settings.UserTracker; import java.util.List; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; /** * Manages the priority which lets {@link TileServices} make decisions about which tiles @@ -72,6 +75,8 @@ public class TileServiceManager { private boolean mPendingBind = true; private boolean mStarted = false; + private final AtomicBoolean mListeningFromRequest = new AtomicBoolean(false); + TileServiceManager(TileServices tileServices, Handler handler, ComponentName component, UserTracker userTracker, TileLifecycleManager.Factory tileLifecycleManagerFactory, CustomTileAddedRepository customTileAddedRepository) { @@ -159,15 +164,30 @@ public class TileServiceManager { } } + void onStartListeningFromRequest() { + mListeningFromRequest.set(true); + mStateManager.onStartListening(); + } + public void setLastUpdate(long lastUpdate) { mLastUpdate = lastUpdate; if (mBound && isActiveTile()) { - mStateManager.onStopListening(); - setBindRequested(false); + if (qsCustomTileClickGuaranteedBugFix()) { + if (mListeningFromRequest.compareAndSet(true, false)) { + stopListeningAndUnbind(); + } + } else { + stopListeningAndUnbind(); + } } mServices.recalculateBindAllowance(); } + private void stopListeningAndUnbind() { + mStateManager.onStopListening(); + setBindRequested(false); + } + public void handleDestroy() { setBindAllowed(false); mServices.getContext().unregisterReceiver(mUninstallReceiver); diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index 8278c790226b..d457e88fcf14 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -15,6 +15,8 @@ */ package com.android.systemui.qs.external; +import static com.android.systemui.Flags.qsCustomTileClickGuaranteedBugFix; + import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; @@ -222,9 +224,13 @@ public class TileServices extends IQSService.Stub { return; } service.setBindRequested(true); - try { - service.getTileService().onStartListening(); - } catch (RemoteException e) { + if (qsCustomTileClickGuaranteedBugFix()) { + service.onStartListeningFromRequest(); + } else { + try { + service.getTileService().onStartListening(); + } catch (RemoteException e) { + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt index e3ba36fe6e32..0696fbe996c0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/dagger/PanelsModule.kt @@ -16,8 +16,17 @@ package com.android.systemui.qs.panels.dagger +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.LogBufferFactory +import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepository +import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepositoryImpl import com.android.systemui.qs.panels.data.repository.IconTilesRepository import com.android.systemui.qs.panels.data.repository.IconTilesRepositoryImpl +import com.android.systemui.qs.panels.domain.interactor.GridTypeConsistencyInteractor +import com.android.systemui.qs.panels.domain.interactor.InfiniteGridConsistencyInteractor +import com.android.systemui.qs.panels.domain.interactor.NoopGridConsistencyInteractor +import com.android.systemui.qs.panels.shared.model.GridConsistencyLog import com.android.systemui.qs.panels.shared.model.GridLayoutType import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType import com.android.systemui.qs.panels.ui.compose.GridLayout @@ -31,8 +40,23 @@ import dagger.multibindings.IntoSet interface PanelsModule { @Binds fun bindIconTilesRepository(impl: IconTilesRepositoryImpl): IconTilesRepository + @Binds + fun bindGridLayoutTypeRepository(impl: GridLayoutTypeRepositoryImpl): GridLayoutTypeRepository + + @Binds + fun bindDefaultGridConsistencyInteractor( + impl: NoopGridConsistencyInteractor + ): GridTypeConsistencyInteractor + companion object { @Provides + @SysUISingleton + @GridConsistencyLog + fun providesGridConsistencyLog(factory: LogBufferFactory): LogBuffer { + return factory.create("GridConsistencyLog", 50) + } + + @Provides @IntoSet fun provideGridLayout(gridLayout: InfiniteGridLayout): Pair<GridLayoutType, GridLayout> { return Pair(InfiniteGridLayoutType, gridLayout) @@ -44,5 +68,20 @@ interface PanelsModule { ): Map<GridLayoutType, GridLayout> { return entries.toMap() } + + @Provides + @IntoSet + fun provideGridConsistencyInteractor( + consistencyInteractor: InfiniteGridConsistencyInteractor + ): Pair<GridLayoutType, GridTypeConsistencyInteractor> { + return Pair(InfiniteGridLayoutType, consistencyInteractor) + } + + @Provides + fun provideGridConsistencyInteractorMap( + entries: Set<@JvmSuppressWildcards Pair<GridLayoutType, GridTypeConsistencyInteractor>> + ): Map<GridLayoutType, GridTypeConsistencyInteractor> { + return entries.toMap() + } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt index 02dd33ebdbc2..542d0cbc425e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepository.kt @@ -20,10 +20,16 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.panels.shared.model.GridLayoutType import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType import javax.inject.Inject -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +interface GridLayoutTypeRepository { + val layout: StateFlow<GridLayoutType> +} @SysUISingleton -class GridLayoutTypeRepository @Inject constructor() { - val layout: Flow<GridLayoutType> = flowOf(InfiniteGridLayoutType) +class GridLayoutTypeRepositoryImpl @Inject constructor() : GridLayoutTypeRepository { + private val _layout: MutableStateFlow<GridLayoutType> = MutableStateFlow(InfiniteGridLayoutType) + override val layout = _layout.asStateFlow() } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt index 92f87e78f090..e581bfceb18f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/IconTilesRepository.kt @@ -19,20 +19,20 @@ package com.android.systemui.qs.panels.data.repository import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.pipeline.shared.TileSpec import javax.inject.Inject -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow /** Repository for retrieving the list of [TileSpec] to be displayed as icons. */ interface IconTilesRepository { - val iconTilesSpecs: Flow<Set<TileSpec>> + val iconTilesSpecs: StateFlow<Set<TileSpec>> } @SysUISingleton class IconTilesRepositoryImpl @Inject constructor() : IconTilesRepository { - /** Set of toggleable tiles that are suitable for being shown as an icon. */ - override val iconTilesSpecs: Flow<Set<TileSpec>> = - flowOf( + private val _iconTilesSpecs = + MutableStateFlow( setOf( TileSpec.create("airplane"), TileSpec.create("battery"), @@ -50,4 +50,7 @@ class IconTilesRepositoryImpl @Inject constructor() : IconTilesRepository { TileSpec.create("rotation") ) ) + + /** Set of toggleable tiles that are suitable for being shown as an icon. */ + override val iconTilesSpecs: StateFlow<Set<TileSpec>> = _iconTilesSpecs.asStateFlow() } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/InfiniteGridSizeRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/InfiniteGridSizeRepository.kt new file mode 100644 index 000000000000..43ccdf663478 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/data/repository/InfiniteGridSizeRepository.kt @@ -0,0 +1,30 @@ +/* + * 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.qs.panels.data.repository + +import com.android.systemui.dagger.SysUISingleton +import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow + +@SysUISingleton +class InfiniteGridSizeRepository @Inject constructor() { + // Number of columns in the narrowest state for consistency + private val _columns = MutableStateFlow(4) + val columns: StateFlow<Int> = _columns.asStateFlow() +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt new file mode 100644 index 000000000000..7732092d6bcf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractor.kt @@ -0,0 +1,75 @@ +/* + * 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.qs.panels.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.core.LogLevel +import com.android.systemui.qs.panels.shared.model.GridConsistencyLog +import com.android.systemui.qs.panels.shared.model.GridLayoutType +import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor +import com.android.systemui.qs.pipeline.shared.TileSpec +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch + +@SysUISingleton +class GridConsistencyInteractor +@Inject +constructor( + private val gridLayoutTypeInteractor: GridLayoutTypeInteractor, + private val currentTilesInteractor: CurrentTilesInteractor, + private val consistencyInteractors: + Map<GridLayoutType, @JvmSuppressWildcards GridTypeConsistencyInteractor>, + private val defaultConsistencyInteractor: GridTypeConsistencyInteractor, + @GridConsistencyLog private val logBuffer: LogBuffer, + @Application private val applicationScope: CoroutineScope, +) { + fun start() { + applicationScope.launch { + gridLayoutTypeInteractor.layout.collectLatest { type -> + val consistencyInteractor = + consistencyInteractors[type] ?: defaultConsistencyInteractor + currentTilesInteractor.currentTiles + .map { tiles -> tiles.map { it.spec } } + .collectLatest { tiles -> + val newTiles = consistencyInteractor.reconcileTiles(tiles) + if (newTiles != tiles) { + currentTilesInteractor.setTiles(newTiles) + logChange(newTiles) + } + } + } + } + } + + private fun logChange(tiles: List<TileSpec>) { + logBuffer.log( + LOG_BUFFER_CURRENT_TILES_CHANGE_TAG, + LogLevel.DEBUG, + { str1 = tiles.toString() }, + { "Tiles reordered: $str1" } + ) + } + + private companion object { + const val LOG_BUFFER_CURRENT_TILES_CHANGE_TAG = "GridConsistencyTilesChange" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridTypeConsistencyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridTypeConsistencyInteractor.kt new file mode 100644 index 000000000000..4cdabaedc49e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/GridTypeConsistencyInteractor.kt @@ -0,0 +1,27 @@ +/* + * 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.qs.panels.domain.interactor + +import com.android.systemui.qs.pipeline.shared.TileSpec + +interface GridTypeConsistencyInteractor { + /** + * Given a list of tiles, return the best list of the same tiles (preserving as much order as + * possible, such that it's consistent with the current layout. + */ + fun reconcileTiles(tiles: List<TileSpec>): List<TileSpec> +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt index 1aec193ca029..ccc1c6e9135c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/IconTilesInteractor.kt @@ -20,10 +20,10 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.panels.data.repository.IconTilesRepository import com.android.systemui.qs.pipeline.shared.TileSpec import javax.inject.Inject -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow /** Interactor for retrieving the list of [TileSpec] to be displayed as icons. */ @SysUISingleton class IconTilesInteractor @Inject constructor(repo: IconTilesRepository) { - val iconTilesSpecs: Flow<Set<TileSpec>> = repo.iconTilesSpecs + val iconTilesSpecs: StateFlow<Set<TileSpec>> = repo.iconTilesSpecs } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractor.kt new file mode 100644 index 000000000000..74e906c621cb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractor.kt @@ -0,0 +1,143 @@ +/* + * 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.qs.panels.domain.interactor + +import android.util.Log +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.pipeline.shared.TileSpec +import javax.inject.Inject + +@SysUISingleton +class InfiniteGridConsistencyInteractor +@Inject +constructor( + private val iconTilesInteractor: IconTilesInteractor, + private val gridSizeInteractor: InfiniteGridSizeInteractor +) : GridTypeConsistencyInteractor { + + /** + * Tries to fill in every columns of all rows (except the last row), potentially reordering + * tiles. + */ + override fun reconcileTiles(tiles: List<TileSpec>): List<TileSpec> { + val newTiles: MutableList<TileSpec> = mutableListOf() + val row = TileRow(columns = gridSizeInteractor.columns.value) + val iconTilesSet = iconTilesInteractor.iconTilesSpecs.value + val tilesQueue = + ArrayDeque( + tiles.map { + SizedTile( + it, + width = + if (iconTilesSet.contains(it)) { + 1 + } else { + 2 + } + ) + } + ) + + while (tilesQueue.isNotEmpty()) { + if (row.isFull()) { + newTiles.addAll(row.tileSpecs()) + row.clear() + } + + val tile = tilesQueue.removeFirst() + + // If the tile fits in the row, add it. + if (!row.maybeAddTile(tile)) { + // If the tile does not fit the row, find an icon tile to move. + // We'll try to either add an icon tile from the queue to complete the row, or + // remove an icon tile from the current row to free up space. + + val iconTile: SizedTile? = tilesQueue.firstOrNull { it.width == 1 } + if (iconTile != null) { + tilesQueue.remove(iconTile) + tilesQueue.addFirst(tile) + row.maybeAddTile(iconTile) + } else { + val tileToRemove: SizedTile? = row.findLastIconTile() + if (tileToRemove != null) { + row.removeTile(tileToRemove) + row.maybeAddTile(tile) + + // Moving the icon tile to the end because there's no other + // icon tiles in the queue. + tilesQueue.addLast(tileToRemove) + } else { + // If the row does not have an icon tile, add the incomplete row. + // Note: this shouldn't happen because an icon tile is guaranteed to be in a + // row that doesn't have enough space for a large tile. + val tileSpecs = row.tileSpecs() + Log.wtf(TAG, "Uneven row does not have an icon tile to remove: $tileSpecs") + newTiles.addAll(tileSpecs) + row.clear() + tilesQueue.addFirst(tile) + } + } + } + } + + // Add last row that might be incomplete + newTiles.addAll(row.tileSpecs()) + + return newTiles.toList() + } + + /** Tile with a width representing the number of columns it should take. */ + private data class SizedTile(val spec: TileSpec, val width: Int) + + private class TileRow(private val columns: Int) { + private var availableColumns = columns + private val tiles: MutableList<SizedTile> = mutableListOf() + + fun tileSpecs(): List<TileSpec> { + return tiles.map { it.spec } + } + + fun maybeAddTile(tile: SizedTile): Boolean { + if (availableColumns - tile.width >= 0) { + tiles.add(tile) + availableColumns -= tile.width + return true + } + return false + } + + fun findLastIconTile(): SizedTile? { + return tiles.findLast { it.width == 1 } + } + + fun removeTile(tile: SizedTile) { + tiles.remove(tile) + availableColumns += tile.width + } + + fun clear() { + tiles.clear() + availableColumns = columns + } + + fun isFull(): Boolean = availableColumns == 0 + } + + private companion object { + const val TAG = "InfiniteGridConsistencyInteractor" + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridSizeInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridSizeInteractor.kt new file mode 100644 index 000000000000..13c6072340c6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridSizeInteractor.kt @@ -0,0 +1,27 @@ +/* + * 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.qs.panels.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.panels.data.repository.InfiniteGridSizeRepository +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow + +@SysUISingleton +class InfiniteGridSizeInteractor @Inject constructor(repo: InfiniteGridSizeRepository) { + val columns: StateFlow<Int> = repo.columns +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractor.kt new file mode 100644 index 000000000000..0386a6ab20d6 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractor.kt @@ -0,0 +1,27 @@ +/* + * 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.qs.panels.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.pipeline.shared.TileSpec +import javax.inject.Inject + +/** [GridTypeConsistencyInteractor] implementation that doesn't do any changes to tiles. */ +@SysUISingleton +class NoopGridConsistencyInteractor @Inject constructor() : GridTypeConsistencyInteractor { + override fun reconcileTiles(tiles: List<TileSpec>): List<TileSpec> = tiles +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridConsistencyLog.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridConsistencyLog.kt new file mode 100644 index 000000000000..884cde35a1aa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/shared/model/GridConsistencyLog.kt @@ -0,0 +1,24 @@ +/* + * 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.qs.panels.shared.model + +import javax.inject.Qualifier + +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class GridConsistencyLog() diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt index 5c17fd1bf94e..3bda7757f8e5 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditMode.kt @@ -20,9 +20,9 @@ import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.qs.panels.ui.viewmodel.EditModeViewModel @Composable @@ -30,8 +30,8 @@ fun EditMode( viewModel: EditModeViewModel, modifier: Modifier = Modifier, ) { - val gridLayout by viewModel.gridLayout.collectAsState() - val tiles by viewModel.tiles.collectAsState(emptyList()) + val gridLayout by viewModel.gridLayout.collectAsStateWithLifecycle() + val tiles by viewModel.tiles.collectAsStateWithLifecycle(emptyList()) BackHandler { viewModel.stopEditing() } diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt index 86cc6f522dd9..bac0f604e294 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/InfiniteGridLayout.kt @@ -53,7 +53,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -66,13 +65,13 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.integerResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.onClick import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.Expandable import com.android.compose.theme.colorAttr import com.android.systemui.common.shared.model.Icon @@ -80,6 +79,7 @@ import com.android.systemui.common.ui.compose.Icon import com.android.systemui.common.ui.compose.load import com.android.systemui.dagger.SysUISingleton import com.android.systemui.qs.panels.domain.interactor.IconTilesInteractor +import com.android.systemui.qs.panels.domain.interactor.InfiniteGridSizeInteractor import com.android.systemui.qs.panels.ui.viewmodel.ActiveTileColorAttributes import com.android.systemui.qs.panels.ui.viewmodel.AvailableEditActions import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel @@ -97,8 +97,12 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.flow.mapLatest @SysUISingleton -class InfiniteGridLayout @Inject constructor(private val iconTilesInteractor: IconTilesInteractor) : - GridLayout { +class InfiniteGridLayout +@Inject +constructor( + private val iconTilesInteractor: IconTilesInteractor, + private val gridSizeInteractor: InfiniteGridSizeInteractor +) : GridLayout { private object TileType @@ -112,10 +116,10 @@ class InfiniteGridLayout @Inject constructor(private val iconTilesInteractor: Ic tiles.forEach { it.startListening(token) } onDispose { tiles.forEach { it.stopListening(token) } } } - val iconTilesSpecs by - iconTilesInteractor.iconTilesSpecs.collectAsState(initial = emptySet()) + val iconTilesSpecs by iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle() + val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle() - TileLazyGrid(modifier) { + TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) { items( tiles.size, span = { index -> @@ -146,7 +150,7 @@ class InfiniteGridLayout @Inject constructor(private val iconTilesInteractor: Ic val state: TileUiState by tile.state .mapLatest { it.toUiState() } - .collectAsState(initial = tile.currentState.toUiState()) + .collectAsStateWithLifecycle(initialValue = tile.currentState.toUiState()) val context = LocalContext.current Expandable( @@ -197,11 +201,15 @@ class InfiniteGridLayout @Inject constructor(private val iconTilesInteractor: Ic val addTileToEnd: (TileSpec) -> Unit by rememberUpdatedState { onAddTile(it, POSITION_AT_END) } - val iconOnlySpecs by iconTilesInteractor.iconTilesSpecs.collectAsState(initial = emptySet()) + val iconOnlySpecs by + iconTilesInteractor.iconTilesSpecs.collectAsStateWithLifecycle( + initialValue = emptySet() + ) val isIconOnly: (TileSpec) -> Boolean = remember(iconOnlySpecs) { { tileSpec: TileSpec -> tileSpec in iconOnlySpecs } } + val columns by gridSizeInteractor.columns.collectAsStateWithLifecycle() - TileLazyGrid(modifier = modifier) { + TileLazyGrid(modifier = modifier, columns = GridCells.Fixed(columns)) { // These Text are just placeholders to see the different sections. Not final UI. item(span = { GridItemSpan(maxLineSpan) }) { Text("Current tiles", color = Color.White) @@ -385,11 +393,11 @@ private fun TileIcon( @Composable private fun TileLazyGrid( modifier: Modifier = Modifier, + columns: GridCells, content: LazyGridScope.() -> Unit, ) { LazyVerticalGrid( - columns = - GridCells.Fixed(integerResource(R.integer.quick_settings_infinite_grid_num_columns)), + columns = columns, verticalArrangement = spacedBy(dimensionResource(R.dimen.qs_tile_margin_vertical)), horizontalArrangement = spacedBy(dimensionResource(R.dimen.qs_tile_margin_horizontal)), modifier = modifier, diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt index 2f32d7264350..2dab7c3d61ca 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileGrid.kt @@ -17,15 +17,15 @@ package com.android.systemui.qs.panels.ui.compose import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel @Composable fun TileGrid(viewModel: TileGridViewModel, modifier: Modifier = Modifier) { - val gridLayout by viewModel.gridLayout.collectAsState() - val tiles by viewModel.tileViewModels.collectAsState(emptyList()) + val gridLayout by viewModel.gridLayout.collectAsStateWithLifecycle() + val tiles by viewModel.tileViewModels.collectAsStateWithLifecycle(emptyList()) gridLayout.TileGrid(tiles, modifier) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt index af1d195516e7..c8fbeb50b039 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/startable/QSPipelineCoreStartable.kt @@ -18,6 +18,8 @@ package com.android.systemui.qs.pipeline.domain.startable import com.android.systemui.CoreStartable import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.flags.NewQsUI +import com.android.systemui.qs.panels.domain.interactor.GridConsistencyInteractor import com.android.systemui.qs.pipeline.domain.interactor.AccessibilityTilesInteractor import com.android.systemui.qs.pipeline.domain.interactor.AutoAddInteractor import com.android.systemui.qs.pipeline.domain.interactor.CurrentTilesInteractor @@ -34,6 +36,7 @@ constructor( private val autoAddInteractor: AutoAddInteractor, private val featureFlags: QSPipelineFlagsRepository, private val restoreReconciliationInteractor: RestoreReconciliationInteractor, + private val gridConsistencyInteractor: GridConsistencyInteractor, ) : CoreStartable { override fun start() { @@ -41,6 +44,10 @@ constructor( accessibilityTilesInteractor.init(currentTilesInteractor) autoAddInteractor.init(currentTilesInteractor) restoreReconciliationInteractor.start() + + if (NewQsUI.isEnabled) { + gridConsistencyInteractor.start() + } } } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt index ffa3b543736b..4c210804b0c0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/viewmodel/QSTileViewModelFactory.kt @@ -25,10 +25,13 @@ import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor import com.android.systemui.qs.tiles.base.logging.QSTileLogger +import com.android.systemui.qs.tiles.impl.custom.di.CustomTileComponent +import com.android.systemui.qs.tiles.impl.custom.di.QSTileConfigModule +import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel import com.android.systemui.qs.tiles.impl.di.QSTileComponent -import com.android.systemui.qs.tiles.viewmodel.QSTileConfig import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel import com.android.systemui.user.data.repository.UserRepository import com.android.systemui.util.time.SystemClock import javax.inject.Inject @@ -47,7 +50,7 @@ sealed interface QSTileViewModelFactory<T> { * binding them together. This achieves a DI scope that lives along the instance of * [QSTileViewModelImpl]. */ - class Component<T> + class Component @Inject constructor( private val disabledByPolicyInteractor: DisabledByPolicyInteractor, @@ -58,7 +61,8 @@ sealed interface QSTileViewModelFactory<T> { private val qsTileConfigProvider: QSTileConfigProvider, private val systemClock: SystemClock, @Background private val backgroundDispatcher: CoroutineDispatcher, - ) : QSTileViewModelFactory<T> { + private val customTileComponentBuilder: CustomTileComponent.Builder, + ) : QSTileViewModelFactory<CustomTileDataModel> { /** * Creates [QSTileViewModelImpl] based on the interactors obtained from [QSTileComponent]. @@ -66,10 +70,10 @@ sealed interface QSTileViewModelFactory<T> { */ fun create( tileSpec: TileSpec, - componentFactory: (config: QSTileConfig) -> QSTileComponent<T> - ): QSTileViewModelImpl<T> { + ): QSTileViewModel { val config = qsTileConfigProvider.getConfig(tileSpec.spec) - val component = componentFactory(config) + val component = + customTileComponentBuilder.qsTileConfigModule(QSTileConfigModule(config)).build() return QSTileViewModelImpl( config, component::userActionInteractor, diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt index 5122e1feabfc..f65fdb540527 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/di/NewQSTileFactory.kt @@ -22,9 +22,6 @@ import com.android.systemui.plugins.qs.QSTile import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory -import com.android.systemui.qs.tiles.impl.custom.di.CustomTileComponent -import com.android.systemui.qs.tiles.impl.custom.di.QSTileConfigModule -import com.android.systemui.qs.tiles.impl.custom.domain.entity.CustomTileDataModel import com.android.systemui.qs.tiles.viewmodel.QSTileConfigProvider import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel import com.android.systemui.qs.tiles.viewmodel.QSTileViewModelAdapter @@ -41,8 +38,7 @@ constructor( private val adapterFactory: QSTileViewModelAdapter.Factory, private val tileMap: Map<String, @JvmSuppressWildcards Provider<@JvmSuppressWildcards QSTileViewModel>>, - private val customTileComponentBuilder: CustomTileComponent.Builder, - private val customTileViewModelFactory: QSTileViewModelFactory.Component<CustomTileDataModel>, + private val customTileViewModelFactory: QSTileViewModelFactory.Component, ) : QSFactory { init { @@ -68,7 +64,5 @@ constructor( } private fun createCustomTileViewModel(spec: TileSpec.CustomTileSpec): QSTileViewModel = - customTileViewModelFactory.create(spec) { config -> - customTileComponentBuilder.qsTileConfigModule(QSTileConfigModule(config)).build() - } + customTileViewModelFactory.create(spec) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt index 17698f9d8647..6cf2e52ff3d9 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt @@ -29,7 +29,7 @@ import com.android.compose.animation.scene.UserActionResult import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor -import com.android.systemui.media.controls.domain.pipeline.MediaDataManager +import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.ui.adapter.QSSceneAdapter @@ -63,7 +63,7 @@ constructor( private val footerActionsViewModelFactory: FooterActionsViewModel.Factory, private val footerActionsController: FooterActionsController, sceneBackInteractor: SceneBackInteractor, - val mediaDataManager: MediaDataManager, + val mediaCarouselInteractor: MediaCarouselInteractor, ) { private val backScene: StateFlow<SceneKey> = sceneBackInteractor.backScene @@ -101,6 +101,8 @@ constructor( ), ) + val isMediaVisible: StateFlow<Boolean> = mediaCarouselInteractor.hasAnyMediaOrRecommendation + private fun destinationScenes( isUnlocked: Boolean, canSwipeToDismiss: Boolean?, @@ -143,9 +145,4 @@ constructor( } return footerActionsViewModelFactory.create(lifecycleOwner) } - - fun isMediaVisible(): Boolean { - // TODO(b/328207006): use new pipeline to handle updates while visible - return mediaDataManager.hasAnyMediaOrRecommendation() - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index faf2bbc1ba3b..e4cb211a430f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -108,6 +108,7 @@ import com.android.systemui.shade.shared.model.ShadeMode; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.system.QuickStepContract; +import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; import com.android.systemui.shared.system.smartspace.ISysuiUnlockAnimationController; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.NotificationShadeWindowController; @@ -117,6 +118,8 @@ import com.android.systemui.unfold.progress.UnfoldTransitionProgressForwarder; import com.android.wm.shell.desktopmode.DesktopModeStatus; import com.android.wm.shell.sysui.ShellInterface; +import dagger.Lazy; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -128,8 +131,6 @@ import java.util.function.Supplier; import javax.inject.Inject; import javax.inject.Provider; -import dagger.Lazy; - /** * Class to send information from overview to launcher with a binder. */ @@ -414,7 +415,13 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis @Override public void toggleNotificationPanel() { verifyCallerAndClearCallingIdentityPostMain("toggleNotificationPanel", () -> - mCommandQueue.togglePanel()); + mCommandQueue.toggleNotificationsPanel()); + } + + @Override + public void toggleQuickSettingsPanel() { + verifyCallerAndClearCallingIdentityPostMain("toggleQuickSettingsPanel", () -> + mCommandQueue.toggleQuickSettingsPanel()); } private boolean verifyCaller(String reason) { @@ -765,7 +772,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis } } - private void notifySystemUiStateFlags(int flags) { + private void notifySystemUiStateFlags(@SystemUiStateFlags long flags) { if (SysUiState.DEBUG) { Log.d(TAG_OPS, "Notifying sysui state change to overview service: proxy=" + mOverviewProxy + " flags=" + flags); diff --git a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt index 4e290e699ac4..6694878cea74 100644 --- a/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt +++ b/packages/SystemUI/src/com/android/systemui/recordissue/IssueRecordingService.kt @@ -20,7 +20,6 @@ import android.app.IActivityManager import android.app.NotificationManager import android.content.Context import android.content.Intent -import android.content.pm.LauncherApps import android.content.res.Resources import android.net.Uri import android.os.Handler @@ -63,7 +62,6 @@ constructor( private val panelInteractor: PanelInteractor, private val issueRecordingState: IssueRecordingState, private val iActivityManager: IActivityManager, - private val launcherApps: LauncherApps, ) : RecordingService( controller, @@ -85,7 +83,7 @@ constructor( when (intent?.action) { ACTION_START -> { TraceUtils.traceStart( - contentResolver, + this, DEFAULT_TRACE_TAGS, DEFAULT_BUFFER_SIZE, DEFAULT_IS_INCLUDING_WINSCOPE, @@ -104,11 +102,7 @@ constructor( } ACTION_STOP, ACTION_STOP_NOTIF -> { - // ViewCapture needs to save it's data before it is disabled, or else the data will - // be lost. This is expected to change in the near future, and when that happens - // this line should be removed. - launcherApps.saveViewCaptureData() - TraceUtils.traceStop(contentResolver) + TraceUtils.traceStop(this) issueRecordingState.isRecording = false } ACTION_SHARE -> { @@ -142,7 +136,7 @@ constructor( private fun shareRecording(screenRecording: Uri?) { val traces = - TraceUtils.traceDump(contentResolver, TRACE_FILE_NAME).getOrElse { + TraceUtils.traceDump(this, TRACE_FILE_NAME).getOrElse { Log.v( TAG, "Traces were not present. This can happen if users double" + diff --git a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt index eabc42b02665..3e2c6306467f 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/data/repository/SceneContainerRepository.kt @@ -21,6 +21,7 @@ package com.android.systemui.scene.data.repository import com.android.compose.animation.scene.ObservableTransitionState import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.TransitionKey +import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.scene.shared.model.SceneContainerConfig import com.android.systemui.scene.shared.model.SceneDataSource @@ -36,6 +37,7 @@ import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.stateIn +@SysUISingleton /** Source of truth for scene framework application state. */ class SceneContainerRepository @Inject diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt index 08efe39d7674..0d0f6e069d2d 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneInteractor.kt @@ -55,6 +55,18 @@ constructor( private val deviceUnlockedInteractor: DeviceUnlockedInteractor, ) { + interface OnSceneAboutToChangeListener { + + /** + * Notifies that the scene is about to change to [toScene]. + * + * The implementation can choose to consume the [sceneState] to prepare the incoming scene. + */ + fun onSceneAboutToChange(toScene: SceneKey, sceneState: Any?) + } + + private val onSceneAboutToChangeListener = mutableSetOf<OnSceneAboutToChangeListener>() + /** * The current scene. * @@ -149,6 +161,10 @@ constructor( return repository.allSceneKeys() } + fun registerSceneStateProcessor(processor: OnSceneAboutToChangeListener) { + onSceneAboutToChangeListener.add(processor) + } + /** * Requests a scene change to the given scene. * @@ -161,6 +177,7 @@ constructor( toScene: SceneKey, loggingReason: String, transitionKey: TransitionKey? = null, + sceneState: Any? = null, ) { val currentSceneKey = currentScene.value if ( @@ -180,6 +197,7 @@ constructor( isInstant = false, ) + onSceneAboutToChangeListener.forEach { it.onSceneAboutToChange(toScene, sceneState) } repository.changeScene(toScene, transitionKey) } 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 4a6427794def..3ce12dddb08e 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 @@ -234,7 +234,7 @@ constructor( bouncerInteractor.onImeHiddenByUser.collectLatest { if (sceneInteractor.currentScene.value == Scenes.Bouncer) { sceneInteractor.changeScene( - toScene = Scenes.Lockscreen, + toScene = Scenes.Lockscreen, // TODO(b/336581871): add sceneState? loggingReason = "IME hidden", ) } @@ -252,6 +252,7 @@ constructor( when { isAnySimLocked -> { switchToScene( + // TODO(b/336581871): add sceneState? targetSceneKey = Scenes.Bouncer, loggingReason = "Need to authenticate locked SIM card." ) @@ -259,6 +260,7 @@ constructor( unlockStatus.isUnlocked && deviceEntryInteractor.canSwipeToEnter.value == false -> { switchToScene( + // TODO(b/336581871): add sceneState? targetSceneKey = Scenes.Gone, loggingReason = "All SIM cards unlocked and device already unlocked and " + @@ -267,6 +269,7 @@ constructor( } else -> { switchToScene( + // TODO(b/336581871): add sceneState? targetSceneKey = Scenes.Lockscreen, loggingReason = "All SIM cards unlocked and device still locked" + @@ -325,7 +328,8 @@ constructor( Scenes.Gone to "device was unlocked in Bouncer scene" } else { val prevScene = previousScene.value - (prevScene ?: Scenes.Gone) to + (prevScene + ?: Scenes.Gone) to "device was unlocked in Bouncer scene, from sceneKey=$prevScene" } isOnLockscreen -> @@ -364,6 +368,7 @@ constructor( powerInteractor.isAsleep.collect { isAsleep -> if (isAsleep) { switchToScene( + // TODO(b/336581871): add sceneState? targetSceneKey = Scenes.Lockscreen, loggingReason = "device is starting to sleep", ) diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt index 0603d21fa2a6..ef393e4858e2 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt @@ -24,8 +24,8 @@ import com.android.compose.animation.scene.TransitionKey * These are the subset of transitions that can be referenced by key when asking for a scene change. */ object TransitionKeys { - /** Reference to the gone to shade transition with split shade enabled. */ - val GoneToSplitShade = TransitionKey("GoneToSplitShade") + /** Reference to the gone/lockscreen to shade transition with split shade enabled. */ + val ToSplitShade = TransitionKey("GoneToSplitShade") /** Reference to a scene transition that can collapse the shade scene instantly. */ val CollapseShadeInstantly = TransitionKey("CollapseShadeInstantly") diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt index 016fe572894c..99118bcfc322 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt @@ -24,7 +24,7 @@ import com.android.compose.animation.scene.UserActionResult import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.scene.shared.model.Scenes -import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade +import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.shared.model.ShadeMode import javax.inject.Inject @@ -73,7 +73,7 @@ constructor( val downSceneKey = if (shadeMode is ShadeMode.Dual) Scenes.NotificationsShade else Scenes.Shade - val downTransitionKey = GoneToSplitShade.takeIf { shadeMode is ShadeMode.Split } + val downTransitionKey = ToSplitShade.takeIf { shadeMode is ShadeMode.Split } this[Swipe(direction = SwipeDirection.Down)] = UserActionResult(downSceneKey, downTransitionKey) } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt index 4eca51d47a36..4ab09185fcdd 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentExecutor.kt @@ -33,10 +33,11 @@ import android.view.WindowManager import android.view.WindowManagerGlobal import com.android.app.tracing.coroutines.launch import com.android.internal.infra.ServiceConnector -import com.android.systemui.Flags.screenshotActionDismissSystemWindows +import com.android.systemui.Flags import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.screenshot.proxy.SystemUiProxy import com.android.systemui.settings.DisplayTracker import com.android.systemui.shared.system.ActivityManagerWrapper import com.android.systemui.statusbar.phone.CentralSurfaces @@ -54,8 +55,8 @@ constructor( private val activityManagerWrapper: ActivityManagerWrapper, @Application private val applicationScope: CoroutineScope, @Main private val mainDispatcher: CoroutineDispatcher, + private val systemUiProxy: SystemUiProxy, private val displayTracker: DisplayTracker, - private val keyguardController: ScreenshotKeyguardController, ) { /** * Execute the given intent with startActivity while performing operations for screenshot action @@ -83,14 +84,12 @@ constructor( options: ActivityOptions?, transitionCoordinator: ExitTransitionCoordinator?, ) { - if (screenshotActionDismissSystemWindows()) { - keyguardController.dismiss() + if (Flags.fixScreenshotActionDismissSystemWindows()) { activityManagerWrapper.closeSystemWindows( CentralSurfaces.SYSTEM_DIALOG_REASON_SCREENSHOT ) - } else { - dismissKeyguard() } + systemUiProxy.dismissKeyguard() transitionCoordinator?.startExit() if (user == myUserHandle()) { @@ -110,27 +109,6 @@ constructor( } } - private val proxyConnector: ServiceConnector<IScreenshotProxy> = - ServiceConnector.Impl( - context, - Intent(context, ScreenshotProxyService::class.java), - Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE, - context.userId, - IScreenshotProxy.Stub::asInterface, - ) - - private suspend fun dismissKeyguard() { - val completion = CompletableDeferred<Unit>() - val onDoneBinder = - object : IOnDoneCallback.Stub() { - override fun onDone(success: Boolean) { - completion.complete(Unit) - } - } - proxyConnector.post { it.dismissKeyguard(onDoneBinder) } - completion.await() - } - private fun getCrossProfileConnector(user: UserHandle): ServiceConnector<ICrossProfileService> = ServiceConnector.Impl<ICrossProfileService>( context, diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt index ef1d87da47be..a1dd4157d996 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt @@ -40,6 +40,7 @@ import dagger.assisted.AssistedInject */ interface ScreenshotActionsProvider { fun onScrollChipReady(onClick: Runnable) + fun onScrollChipInvalidated() fun setCompletedScreenshot(result: ScreenshotSavedResult) /** @@ -67,6 +68,8 @@ constructor( @Assisted val requestId: String, @Assisted val actionExecutor: ActionExecutor, ) : ScreenshotActionsProvider { + private var addedScrollChip = false + private var onScrollClick: Runnable? = null private var pendingAction: ((ScreenshotSavedResult) -> Unit)? = null private var result: ScreenshotSavedResult? = null @@ -122,18 +125,26 @@ constructor( } override fun onScrollChipReady(onClick: Runnable) { - viewModel.addAction( - ActionButtonAppearance( - AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_scroll), - context.resources.getString(R.string.screenshot_scroll_label), - context.resources.getString(R.string.screenshot_scroll_label), - ), - showDuringEntrance = true, - ) { - onClick.run() + onScrollClick = onClick + if (!addedScrollChip) { + viewModel.addAction( + ActionButtonAppearance( + AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_scroll), + context.resources.getString(R.string.screenshot_scroll_label), + context.resources.getString(R.string.screenshot_scroll_label), + ), + showDuringEntrance = true, + ) { + onScrollClick?.run() + } + addedScrollChip = true } } + override fun onScrollChipInvalidated() { + onScrollClick = null + } + override fun setCompletedScreenshot(result: ScreenshotSavedResult) { if (this.result != null) { Log.e(TAG, "Got a second completed screenshot for existing request!") diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java index bd90de230d5f..2f026aee64d8 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java @@ -586,7 +586,11 @@ public class ScreenshotController { if (mConfigChanges.applyNewConfig(mContext.getResources())) { // Hide the scroll chip until we know it's available in this // orientation - mViewProxy.hideScrollChip(); + if (screenshotShelfUi2()) { + mActionsProvider.onScrollChipInvalidated(); + } else { + mViewProxy.hideScrollChip(); + } // Delay scroll capture eval a bit to allow the underlying activity // to set up in the new orientation. mScreenshotHandler.postDelayed( diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt deleted file mode 100644 index 7696bbe3763e..000000000000 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotKeyguardController.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.screenshot - -import android.content.Context -import android.content.Intent -import com.android.internal.infra.ServiceConnector -import javax.inject.Inject -import kotlinx.coroutines.CompletableDeferred - -open class ScreenshotKeyguardController @Inject constructor(context: Context) { - private val proxyConnector: ServiceConnector<IScreenshotProxy> = - ServiceConnector.Impl( - context, - Intent(context, ScreenshotProxyService::class.java), - Context.BIND_AUTO_CREATE or Context.BIND_WAIVE_PRIORITY or Context.BIND_NOT_VISIBLE, - context.userId, - IScreenshotProxy.Stub::asInterface - ) - - suspend fun dismiss() { - val completion = CompletableDeferred<Unit>() - val onDoneBinder = - object : IOnDoneCallback.Stub() { - override fun onDone(success: Boolean) { - completion.complete(Unit) - } - } - proxyConnector.post { it.dismissKeyguard(onDoneBinder) } - completion.await() - } -} diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt index 412b08905ae9..846884fe4cf9 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotShelfViewProxy.kt @@ -31,6 +31,7 @@ import android.view.WindowInsets import android.view.WindowManager import android.window.OnBackInvokedCallback import android.window.OnBackInvokedDispatcher +import androidx.appcompat.content.res.AppCompatResources import androidx.core.animation.doOnEnd import androidx.core.animation.doOnStart import com.android.internal.logging.UiEventLogger @@ -58,6 +59,7 @@ constructor( private val logger: UiEventLogger, private val viewModel: ScreenshotViewModel, private val windowManager: WindowManager, + shelfViewBinder: ScreenshotShelfViewBinder, private val thumbnailObserver: ThumbnailObserver, @Assisted private val context: Context, @Assisted private val displayId: Int @@ -69,7 +71,17 @@ constructor( override var callbacks: ScreenshotView.ScreenshotViewCallback? = null override var screenshot: ScreenshotData? = null set(value) { - viewModel.setScreenshotBitmap(value?.bitmap) + value?.let { + viewModel.setScreenshotBitmap(it.bitmap) + val badgeBg = + AppCompatResources.getDrawable(context, R.drawable.overlay_badge_background) + val user = it.userHandle + if (badgeBg != null && user != null) { + viewModel.setScreenshotBadge( + context.packageManager.getUserBadgedIcon(badgeBg, user) + ) + } + } field = value } @@ -81,12 +93,13 @@ constructor( private val animationController = ScreenshotAnimationController(view) init { - ScreenshotShelfViewBinder.bind( + shelfViewBinder.bind( view, viewModel, LayoutInflater.from(context), onDismissalRequested = { event, velocity -> requestDismissal(event, velocity) }, - onDismissalCancelled = { animationController.getSwipeReturnAnimation().start() } + onDismissalCancelled = { animationController.getSwipeReturnAnimation().start() }, + onUserInteraction = { callbacks?.onUserInteraction() } ) view.updateInsets(windowManager.currentWindowMetrics.windowInsets) addPredictiveBackListener { requestDismissal(SCREENSHOT_DISMISSED_OTHER) } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt index 916d50fd75b1..969cf482be90 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/ScreenshotShelfView.kt @@ -22,6 +22,8 @@ import android.graphics.Insets import android.graphics.Rect import android.graphics.Region import android.util.AttributeSet +import android.view.GestureDetector +import android.view.GestureDetector.SimpleOnGestureListener import android.view.MotionEvent import android.view.View import android.view.ViewGroup @@ -30,7 +32,6 @@ import android.widget.FrameLayout import android.widget.ImageView import com.android.systemui.res.R import com.android.systemui.screenshot.FloatingWindowUtil -import kotlin.math.max class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : FrameLayout(context, attrs) { @@ -39,11 +40,50 @@ class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : private lateinit var screenshotStatic: ViewGroup var onTouchInterceptListener: ((MotionEvent) -> Boolean)? = null + var userInteractionCallback: (() -> Unit)? = null + private val displayMetrics = context.resources.displayMetrics private val tmpRect = Rect() private lateinit var actionsContainerBackground: View + private lateinit var actionsContainer: View private lateinit var dismissButton: View + // Prepare an internal `GestureDetector` to determine when we can initiate a touch-interception + // session (with the client's provided `onTouchInterceptListener`). We delegate out to their + // listener only for gestures that can't be handled by scrolling our `actionsContainer`. + private val gestureDetector = + GestureDetector( + context, + object : SimpleOnGestureListener() { + override fun onScroll( + ev1: MotionEvent?, + ev2: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean { + actionsContainer.getBoundsOnScreen(tmpRect) + val touchedInActionsContainer = + tmpRect.contains(ev2.rawX.toInt(), ev2.rawY.toInt()) + val canHandleInternallyByScrolling = + touchedInActionsContainer + && actionsContainer.canScrollHorizontally(distanceX.toInt()) + return !canHandleInternallyByScrolling + } + } + ) + + init { + + // Delegate to the client-provided `onTouchInterceptListener` if we've already initiated + // touch-interception. + setOnTouchListener({ _: View, ev: MotionEvent -> + userInteractionCallback?.invoke() + onTouchInterceptListener?.invoke(ev) ?: false + }) + + gestureDetector.setIsLongpressEnabled(false) + } + override fun onFinishInflate() { super.onFinishInflate() // Get focus so that the key events go to the layout. @@ -52,7 +92,15 @@ class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : blurredScreenshotPreview = requireViewById(R.id.screenshot_preview_blur) screenshotStatic = requireViewById(R.id.screenshot_static) actionsContainerBackground = requireViewById(R.id.actions_container_background) + actionsContainer = requireViewById(R.id.actions_container) dismissButton = requireViewById(R.id.screenshot_dismiss_button) + + // Configure to extend the timeout during ongoing gestures (i.e. scrolls) that are already + // being handled by our child views. + actionsContainer.setOnTouchListener({ _: View, ev: MotionEvent -> + userInteractionCallback?.invoke() + false + }) } fun getTouchRegion(gestureInsets: Insets): Region { @@ -79,6 +127,18 @@ class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : val inPortrait = orientation == Configuration.ORIENTATION_PORTRAIT val cutout = insets.displayCutout val navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars()) + + // When honoring the navbar or other obstacle offsets, include some extra padding above + // the inset itself. + val verticalPadding = + mContext.resources.getDimensionPixelOffset(R.dimen.screenshot_shelf_vertical_margin) + + // Minimum bottom padding to always enforce (e.g. if there's no nav bar) + val minimumBottomPadding = + context.resources.getDimensionPixelOffset( + R.dimen.overlay_action_container_minimum_edge_spacing + ) + if (cutout == null) { screenshotStatic.setPadding(0, 0, 0, navBarInsets.bottom) } else { @@ -86,25 +146,41 @@ class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : if (inPortrait) { screenshotStatic.setPadding( waterfall.left, - max(cutout.safeInsetTop.toDouble(), waterfall.top.toDouble()).toInt(), + max(cutout.safeInsetTop, waterfall.top), waterfall.right, max( - cutout.safeInsetBottom.toDouble(), - max(navBarInsets.bottom.toDouble(), waterfall.bottom.toDouble()) - ) - .toInt() + navBarInsets.bottom + verticalPadding, + cutout.safeInsetBottom + verticalPadding, + waterfall.bottom + verticalPadding, + minimumBottomPadding, + ) ) } else { screenshotStatic.setPadding( - max(cutout.safeInsetLeft.toDouble(), waterfall.left.toDouble()).toInt(), + max(cutout.safeInsetLeft, waterfall.left), waterfall.top, - max(cutout.safeInsetRight.toDouble(), waterfall.right.toDouble()).toInt(), - max(navBarInsets.bottom.toDouble(), waterfall.bottom.toDouble()).toInt() + max(cutout.safeInsetRight, waterfall.right), + max( + navBarInsets.bottom + verticalPadding, + waterfall.bottom + verticalPadding, + minimumBottomPadding, + ) ) } } } + // Max function for two or more params. + private fun max(first: Int, second: Int, vararg items: Int): Int { + var largest = if (first > second) first else second + for (item in items) { + if (item > largest) { + largest = item + } + } + return largest + } + private fun getSwipeRegion(): Region { val swipeRegion = Region() val padding = FloatingWindowUtil.dpToPx(displayMetrics, -1 * TOUCH_PADDING_DP).toInt() @@ -127,10 +203,24 @@ class ScreenshotShelfView(context: Context, attrs: AttributeSet? = null) : private const val TOUCH_PADDING_DP = 12f } + override fun onInterceptHoverEvent(event: MotionEvent): Boolean { + userInteractionCallback?.invoke() + return super.onInterceptHoverEvent(event) + } + override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { - if (onTouchInterceptListener?.invoke(ev) == true) { - return true + userInteractionCallback?.invoke() + + // Let the client-provided listener see all `DOWN` events so that they'll be able to + // interpret the remainder of the gesture, even if interception starts partway-through. + // TODO: is this really necessary? And if we don't go on to start interception, should we + // follow up with `ACTION_CANCEL`? + if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { + onTouchInterceptListener?.invoke(ev) } - return super.onInterceptTouchEvent(ev) + + // Only allow the client-provided touch interceptor to take over the gesture if our + // top-level `GestureDetector` decides not to scroll the action container. + return gestureDetector.onTouchEvent(ev) } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt index 750bd530d9b2..2a98068543ce 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ActionButtonViewBinder.kt @@ -23,8 +23,9 @@ import android.widget.TextView import com.android.systemui.res.R import com.android.systemui.screenshot.ui.TransitioningIconDrawable import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel +import javax.inject.Inject -object ActionButtonViewBinder { +class ActionButtonViewBinder @Inject constructor() { /** Binds the given view to the given view-model */ fun bind(view: View, viewModel: ActionButtonViewModel) { val iconView = view.requireViewById<ImageView>(R.id.overlay_action_chip_icon) @@ -37,6 +38,14 @@ object ActionButtonViewBinder { // models would remove/create separate views. drawable?.setIcon(viewModel.appearance.icon) textView.text = viewModel.appearance.label + + viewModel.appearance.customBackground?.also { + if (it.canApplyTheme()) { + it.applyTheme(view.rootView.context.theme) + } + view.background = it + } + setMargins(iconView, textView, viewModel.appearance.label?.isNotEmpty() ?: false) if (viewModel.onClicked != null) { view.setOnClickListener { viewModel.onClicked.invoke() } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt index 43c0107c12d5..c7bc50cb3802 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/binder/ScreenshotShelfViewBinder.kt @@ -35,16 +35,20 @@ import com.android.systemui.screenshot.ui.viewmodel.ActionButtonViewModel import com.android.systemui.screenshot.ui.viewmodel.AnimationState import com.android.systemui.screenshot.ui.viewmodel.ScreenshotViewModel import com.android.systemui.util.children +import javax.inject.Inject import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -object ScreenshotShelfViewBinder { +class ScreenshotShelfViewBinder +@Inject +constructor(private val buttonViewBinder: ActionButtonViewBinder) { fun bind( view: ScreenshotShelfView, viewModel: ScreenshotViewModel, layoutInflater: LayoutInflater, onDismissalRequested: (event: ScreenshotEvent, velocity: Float?) -> Unit, onDismissalCancelled: () -> Unit, + onUserInteraction: () -> Unit ) { val swipeGestureListener = SwipeGestureListener( @@ -55,6 +59,7 @@ object ScreenshotShelfViewBinder { onCancel = onDismissalCancelled ) view.onTouchInterceptListener = { swipeGestureListener.onMotionEvent(it) } + view.userInteractionCallback = onUserInteraction val previewView: ImageView = view.requireViewById(R.id.screenshot_preview) val previewViewBlur: ImageView = view.requireViewById(R.id.screenshot_preview_blur) @@ -66,6 +71,7 @@ object ScreenshotShelfViewBinder { dismissButton.setOnClickListener { onDismissalRequested(ScreenshotEvent.SCREENSHOT_EXPLICIT_DISMISSAL, null) } + val badgeView = view.requireViewById<ImageView>(R.id.screenshot_badge) // use immediate dispatcher to ensure screenshot bitmap is set before animation view.repeatWhenAttached(Dispatchers.Main.immediate) { @@ -85,6 +91,12 @@ object ScreenshotShelfViewBinder { } } launch { + viewModel.badge.collect { badge -> + badgeView.setImageDrawable(badge) + badgeView.visibility = if (badge != null) View.VISIBLE else View.GONE + } + } + launch { viewModel.previewAction.collect { onClick -> previewView.setOnClickListener { onClick?.invoke() } } @@ -149,14 +161,14 @@ object ScreenshotShelfViewBinder { val currentView: View? = actionsContainer.getChildAt(index) if (action.id == currentView?.tag) { // Same ID, update the display - ActionButtonViewBinder.bind(currentView, action) + buttonViewBinder.bind(currentView, action) } else { // Different ID. Removals have already happened so this must // mean that the new action must be inserted here. val actionButton = layoutInflater.inflate(R.layout.shelf_action_chip, actionsContainer, false) actionsContainer.addView(actionButton, index) - ActionButtonViewBinder.bind(actionButton, action) + buttonViewBinder.bind(actionButton, action) } } } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt index 55a2ad21e292..2982ea011825 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ActionButtonAppearance.kt @@ -19,8 +19,11 @@ package com.android.systemui.screenshot.ui.viewmodel import android.graphics.drawable.Drawable /** Data describing how an action should be shown to the user. */ -data class ActionButtonAppearance( +data class ActionButtonAppearance +@JvmOverloads +constructor( val icon: Drawable?, val label: CharSequence?, val description: CharSequence, + val customBackground: Drawable? = null, ) diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt index 5f36f73f2135..81bc281191ed 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ui/viewmodel/ScreenshotViewModel.kt @@ -17,6 +17,7 @@ package com.android.systemui.screenshot.ui.viewmodel import android.graphics.Bitmap +import android.graphics.drawable.Drawable import android.util.Log import android.view.accessibility.AccessibilityManager import kotlinx.coroutines.flow.MutableStateFlow @@ -25,6 +26,8 @@ import kotlinx.coroutines.flow.StateFlow class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager) { private val _preview = MutableStateFlow<Bitmap?>(null) val preview: StateFlow<Bitmap?> = _preview + private val _badge = MutableStateFlow<Drawable?>(null) + val badge: StateFlow<Drawable?> = _badge private val _previewAction = MutableStateFlow<(() -> Unit)?>(null) val previewAction: StateFlow<(() -> Unit)?> = _previewAction private val _actions = MutableStateFlow(emptyList<ActionButtonViewModel>()) @@ -39,6 +42,10 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager _preview.value = bitmap } + fun setScreenshotBadge(badge: Drawable?) { + _badge.value = badge + } + fun setPreviewAction(onClick: () -> Unit) { _previewAction.value = onClick } @@ -109,6 +116,7 @@ class ScreenshotViewModel(private val accessibilityManager: AccessibilityManager fun reset() { _preview.value = null + _badge.value = null _previewAction.value = null _actions.value = listOf() _animationState.value = AnimationState.NOT_STARTED diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt index 6367d44bd439..ee7b4beec64e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt @@ -40,6 +40,7 @@ import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent import com.android.systemui.communal.dagger.Communal import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.ui.compose.CommunalContainer +import com.android.systemui.communal.ui.compose.CommunalContent import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.communal.util.CommunalColors import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor @@ -50,7 +51,6 @@ import com.android.systemui.res.R import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.SceneDataSourceDelegator import com.android.systemui.shade.domain.interactor.ShadeInteractor -import com.android.systemui.statusbar.phone.SystemUIDialogFactory import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf import com.android.systemui.util.kotlin.BooleanFlowOperators.not @@ -69,12 +69,12 @@ class GlanceableHubContainerController constructor( private val communalInteractor: CommunalInteractor, private val communalViewModel: CommunalViewModel, - private val dialogFactory: SystemUIDialogFactory, private val keyguardInteractor: KeyguardInteractor, private val shadeInteractor: ShadeInteractor, private val powerManager: PowerManager, private val communalColors: CommunalColors, private val ambientTouchComponentFactory: AmbientTouchComponent.Factory, + private val communalContent: CommunalContent, @Communal private val dataSourceDelegator: SceneDataSourceDelegator ) : LifecycleOwner { /** The container view for the hub. This will not be initialized until [initView] is called. */ @@ -180,7 +180,7 @@ constructor( viewModel = communalViewModel, colors = communalColors, dataSourceDelegator = dataSourceDelegator, - dialogFactory = dialogFactory, + content = communalContent, ) } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt index d2c93da671af..884ccef3a080 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt @@ -140,7 +140,7 @@ constructor( private fun animateCollapseShadeInternal() { sceneInteractor.changeScene( - getCollapseDestinationScene(), + getCollapseDestinationScene(), // TODO(b/336581871): add sceneState? "ShadeController.animateCollapseShade", SlightlyFasterShadeCollapse, ) diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt index c9949cdc8ab6..55bd8c6c0834 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeBackActionInteractorImpl.kt @@ -44,6 +44,7 @@ constructor( } else { Scenes.Shade } + // TODO(b/336581871): add sceneState? sceneInteractor.changeScene(key, "animateCollapseQs") } } diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt index d15a488cb582..e4a2424e1ead 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt @@ -27,13 +27,13 @@ import com.android.compose.animation.scene.UserActionResult import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor -import com.android.systemui.media.controls.domain.pipeline.MediaDataManager +import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor import com.android.systemui.qs.FooterActionsController import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.ui.adapter.QSSceneAdapter import com.android.systemui.scene.domain.interactor.SceneInteractor import com.android.systemui.scene.shared.model.Scenes -import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade +import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade import com.android.systemui.settings.brightness.ui.viewModel.BrightnessMirrorViewModel import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.shade.shared.model.ShadeMode @@ -61,7 +61,7 @@ constructor( val shadeHeaderViewModel: ShadeHeaderViewModel, val notifications: NotificationsPlaceholderViewModel, val brightnessMirrorViewModel: BrightnessMirrorViewModel, - val mediaDataManager: MediaDataManager, + val mediaCarouselInteractor: MediaCarouselInteractor, shadeInteractor: ShadeInteractor, private val footerActionsViewModelFactory: FooterActionsViewModel.Factory, private val footerActionsController: FooterActionsController, @@ -109,6 +109,8 @@ constructor( val shadeMode: StateFlow<ShadeMode> = shadeInteractor.shadeMode + val isMediaVisible: StateFlow<Boolean> = mediaCarouselInteractor.hasActiveMediaOrRecommendation + /** * Amount of X-axis translation to apply to various elements as the unfolded foldable is folded * slightly, in pixels. @@ -126,11 +128,6 @@ constructor( sceneInteractor.changeScene(Scenes.Lockscreen, "Shade empty content clicked") } - fun isMediaVisible(): Boolean { - // TODO(b/296122467): handle updates to carousel visibility while scene is still visible - return mediaDataManager.hasActiveMediaOrRecommendation() - } - private val footerActionsControllerInitialized = AtomicBoolean(false) fun getFooterActionsViewModel(lifecycleOwner: LifecycleOwner): FooterActionsViewModel { @@ -153,7 +150,7 @@ constructor( else -> Scenes.Lockscreen } - val upTransitionKey = GoneToSplitShade.takeIf { shadeMode is ShadeMode.Split } + val upTransitionKey = ToSplitShade.takeIf { shadeMode is ShadeMode.Split } val down = Scenes.QuickSettings.takeIf { shadeMode is ShadeMode.Single } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index d955349ffede..c9126161c40f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -134,7 +134,7 @@ public class CommandQueue extends IStatusBar.Stub implements private static final int MSG_DISMISS_KEYBOARD_SHORTCUTS = 32 << MSG_SHIFT; private static final int MSG_HANDLE_SYSTEM_KEY = 33 << MSG_SHIFT; private static final int MSG_SHOW_GLOBAL_ACTIONS = 34 << MSG_SHIFT; - private static final int MSG_TOGGLE_PANEL = 35 << MSG_SHIFT; + private static final int MSG_TOGGLE_NOTIFICATION_PANEL = 35 << MSG_SHIFT; private static final int MSG_SHOW_SHUTDOWN_UI = 36 << MSG_SHIFT; private static final int MSG_SET_TOP_APP_HIDES_STATUS_BAR = 37 << MSG_SHIFT; private static final int MSG_ROTATION_PROPOSAL = 38 << MSG_SHIFT; @@ -180,6 +180,7 @@ public class CommandQueue extends IStatusBar.Stub implements private static final int MSG_SET_QS_TILES = 79 << MSG_SHIFT; private static final int MSG_ENTER_DESKTOP = 80 << MSG_SHIFT; private static final int MSG_SET_SPLITSCREEN_FOCUS = 81 << MSG_SHIFT; + private static final int MSG_TOGGLE_QUICK_SETTINGS_PANEL = 82 << 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; @@ -222,10 +223,33 @@ public class CommandQueue extends IStatusBar.Stub implements */ default void disable(int displayId, @DisableFlags int state1, @Disable2Flags int state2, boolean animate) { } + + /** + * Called to expand Notifications panel with animation. + */ default void animateExpandNotificationsPanel() { } + /** + * Called to collapse Notifications panel with animation. + * @param flags Exclusion flags. See {@link FLAG_EXCLUDE_NONE}. + * @param force True to force the operation. + */ default void animateCollapsePanels(int flags, boolean force) { } - default void togglePanel() { } - default void animateExpandSettingsPanel(String obj) { } + + /** + * Called to toggle Notifications panel. + */ + default void toggleNotificationsPanel() { } + + /** + * Called to expand Quick Settings panel with animation. + * @param subPanel subPanel one wish to expand. + */ + default void animateExpandSettingsPanel(String subPanel) { } + + /** + * Called to toggle Quick Settings panel. + */ + default void toggleQuickSettingsPanel() { } /** * Called to notify IME window status changes. @@ -696,10 +720,10 @@ public class CommandQueue extends IStatusBar.Stub implements } } - public void togglePanel() { + public void toggleNotificationsPanel() { synchronized (mLock) { - mHandler.removeMessages(MSG_TOGGLE_PANEL); - mHandler.obtainMessage(MSG_TOGGLE_PANEL, 0, 0).sendToTarget(); + mHandler.removeMessages(MSG_TOGGLE_NOTIFICATION_PANEL); + mHandler.obtainMessage(MSG_TOGGLE_NOTIFICATION_PANEL, 0, 0).sendToTarget(); } } @@ -710,6 +734,13 @@ public class CommandQueue extends IStatusBar.Stub implements } } + public void toggleQuickSettingsPanel() { + synchronized (mLock) { + mHandler.removeMessages(MSG_TOGGLE_QUICK_SETTINGS_PANEL); + mHandler.obtainMessage(MSG_TOGGLE_QUICK_SETTINGS_PANEL, 0, 0).sendToTarget(); + } + } + @Override public void setImeWindowStatus(int displayId, IBinder token, int vis, int backDisposition, boolean showImeSwitcher) { @@ -1494,9 +1525,9 @@ public class CommandQueue extends IStatusBar.Stub implements mCallbacks.get(i).animateCollapsePanels(msg.arg1, msg.arg2 != 0); } break; - case MSG_TOGGLE_PANEL: + case MSG_TOGGLE_NOTIFICATION_PANEL: for (int i = 0; i < mCallbacks.size(); i++) { - mCallbacks.get(i).togglePanel(); + mCallbacks.get(i).toggleNotificationsPanel(); } break; case MSG_EXPAND_SETTINGS: @@ -1504,6 +1535,11 @@ public class CommandQueue extends IStatusBar.Stub implements mCallbacks.get(i).animateExpandSettingsPanel((String) msg.obj); } break; + case MSG_TOGGLE_QUICK_SETTINGS_PANEL: + for (int i = 0; i < mCallbacks.size(); i++) { + mCallbacks.get(i).toggleQuickSettingsPanel(); + } + break; case MSG_SHOW_IME_BUTTON: args = (SomeArgs) msg.obj; handleShowImeButton(args.argi1 /* displayId */, (IBinder) args.arg1 /* token */, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java index d7d373226d5c..5bf2f41ae453 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java @@ -15,6 +15,8 @@ */ package com.android.systemui.statusbar; +import static com.android.systemui.Flags.mediaControlsUserInitiatedDismiss; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.Notification; @@ -175,14 +177,18 @@ public class NotificationMediaManager implements Dumpable { } @Override - public void onMediaDataRemoved(@NonNull String key) { + public void onMediaDataRemoved(@NonNull String key, boolean userInitiated) { + if (mediaControlsUserInitiatedDismiss() && !userInitiated) { + // Dismissing the notification will send the app's deleteIntent, so ignore if + // this was an automatic removal + Log.d(TAG, "Not dismissing " + key + " because it was removed by the system"); + return; + } mNotifPipeline.getAllNotifs() .stream() .filter(entry -> Objects.equals(entry.getKey(), key)) .findAny() .ifPresent(entry -> { - // TODO(b/160713608): "removing" this notification won't happen and - // won't send the 'deleteIntent' if the notification is ongoing. mNotifCollection.dismissNotification(entry, getDismissedByUserStats(entry)); }); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt index 1a223c110ad5..933eb207e76d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt @@ -18,12 +18,10 @@ package com.android.systemui.statusbar.notification.collection.coordinator -import android.os.SystemProperties import android.os.UserHandle import android.provider.Settings import androidx.annotation.VisibleForTesting import com.android.systemui.Dumpable -import com.android.systemui.Flags.notificationMinimalismPrototype import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dump.DumpManager @@ -41,6 +39,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider +import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.headsUpEvents import com.android.systemui.util.asIndenting @@ -264,7 +263,7 @@ constructor( } private fun unseenFeatureEnabled(): Flow<Boolean> { - if (notificationMinimalismPrototype()) { + if (NotificationMinimalismPrototype.V1.isEnabled) { return flowOf(true) } return secureSettings @@ -342,18 +341,6 @@ constructor( var hasFilteredAnyNotifs = false /** - * the [notificationMinimalismPrototype] will now show seen notifications on the locked - * shade by default, but this property read allows that to be quickly disabled for - * testing - */ - private val minimalismShowOnLockedShade - get() = - SystemProperties.getBoolean( - "persist.notification_minimalism_prototype.show_on_locked_shade", - true - ) - - /** * Encapsulates a definition of "being on the keyguard". Note that these two definitions * are wildly different: [StatusBarState.KEYGUARD] is when on the lock screen and does * not include shade or occluded states, whereas [KeyguardRepository.isKeyguardShowing] @@ -364,7 +351,10 @@ constructor( * allow seen notifications to appear in the locked shade. */ private fun isOnKeyguard(): Boolean = - if (notificationMinimalismPrototype() && minimalismShowOnLockedShade) { + if ( + NotificationMinimalismPrototype.V1.isEnabled && + NotificationMinimalismPrototype.V1.showOnLockedShade + ) { statusBarStateController.state == StatusBarState.KEYGUARD } else { keyguardRepository.isKeyguardShowing() 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 747cb3c8d934..4f1056ce9e57 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 @@ -590,7 +590,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mMenuRow.setAppName(mAppName); } if (mIsSummaryWithChildren) { - if (!AsyncGroupHeaderViewInflation.isEnabled()) { + if (AsyncGroupHeaderViewInflation.isEnabled()) { + mChildrenContainer.updateGroupHeaderExpandState(); + } else { // We create the header from the background thread instead mChildrenContainer.recreateNotificationHeader(mExpandClickListener, isConversation()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt new file mode 100644 index 000000000000..8889a10f5ad1 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationMinimalismPrototype.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.shared + +import android.os.SystemProperties +import com.android.systemui.Flags +import com.android.systemui.flags.FlagToken +import com.android.systemui.flags.RefactorFlagUtils + +/** Helper for reading or using the minimalism prototype flag state. */ +@Suppress("NOTHING_TO_INLINE") +object NotificationMinimalismPrototype { + object V1 { + /** The aconfig flag name */ + const val FLAG_NAME = Flags.FLAG_NOTIFICATION_MINIMALISM_PROTOTYPE + + /** A token used for dependency declaration */ + val token: FlagToken + get() = FlagToken(FLAG_NAME, isEnabled) + + /** Is the heads-up cycling animation enabled */ + @JvmStatic + inline val isEnabled + get() = Flags.notificationMinimalismPrototype() + + /** + * the prototype will now show seen notifications on the locked shade by default, but this + * property read allows that to be quickly disabled for testing + */ + val showOnLockedShade: Boolean + get() = + if (isUnexpectedlyInLegacyMode()) false + else + SystemProperties.getBoolean( + "persist.notification_minimalism_prototype.show_on_locked_shade", + true + ) + + /** gets the configurable max number of notifications */ + val maxNotifs: Int + get() = + if (isUnexpectedlyInLegacyMode()) -1 + else + SystemProperties.getInt( + "persist.notification_minimalism_prototype.lock_screen_max_notifs", + 1 + ) + + /** + * Called to ensure code is only run when the flag is enabled. This protects users from the + * unintended behaviors caused by accidentally running new logic, while also crashing on an + * eng build to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun isUnexpectedlyInLegacyMode() = + RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME) + + /** + * Called to ensure code is only run when the flag is disabled. This will throw an exception + * if the flag is enabled to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index 92c597cf384e..48796d8f8f2d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -439,6 +439,15 @@ public class NotificationChildrenContainer extends ViewGroup Trace.endSection(); } + /** + * Update the expand state of the group header. + */ + public void updateGroupHeaderExpandState() { + if (mGroupHeaderWrapper != null) { + mGroupHeaderWrapper.setExpanded(mChildrenExpanded); + } + } + private void removeGroupHeader() { if (mGroupHeader == null) { return; 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 bfc74250cefe..abbe7d74733d 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 @@ -128,6 +128,7 @@ import com.android.systemui.statusbar.policy.SplitShadeStateController; import com.android.systemui.util.Assert; import com.android.systemui.util.ColorUtilKt; import com.android.systemui.util.DumpUtilsKt; +import com.android.systemui.util.ListenerSet; import com.google.errorprone.annotations.CompileTimeConstant; @@ -254,6 +255,7 @@ public class NotificationStackScrollLayout * The raw amount of the overScroll on the bottom, which is not rubber-banded. */ private float mOverScrolledBottomPixels; + private ListenerSet<Runnable> mStackHeightChangedListeners = new ListenerSet<>(); private NotificationLogger.OnChildLocationsChangedListener mListener; private OnNotificationLocationsChangedListener mLocationsChangedListener; private OnOverscrollTopChangedListener mOverscrollTopChangedListener; @@ -316,7 +318,7 @@ public class NotificationStackScrollLayout = new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - if (SceneContainerFlag.isEnabled() && !mChildrenUpdateRequested) { + if (SceneContainerFlag.isEnabled()) { getViewTreeObserver().removeOnPreDrawListener(this); return true; } @@ -1083,6 +1085,10 @@ public class NotificationStackScrollLayout for (int i = 0; i < size; i++) { measureChild(getChildAt(i), childWidthSpec, childHeightSpec); } + if (SceneContainerFlag.isEnabled()) { + setMaxLayoutHeight(getMeasuredHeight()); + updateContentHeight(); + } Trace.endSection(); } @@ -1092,6 +1098,22 @@ public class NotificationStackScrollLayout super.requestLayout(); } + private void notifyStackHeightChangedListeners() { + for (Runnable listener : mStackHeightChangedListeners) { + listener.run(); + } + } + + @Override + public void addStackHeightChangedListener(@NonNull Runnable runnable) { + mStackHeightChangedListeners.addIfAbsent(runnable); + } + + @Override + public void removeStackHeightChangedListener(@NonNull Runnable runnable) { + mStackHeightChangedListeners.remove(runnable); + } + @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (!mSuppressChildrenMeasureAndLayout) { @@ -1110,8 +1132,10 @@ public class NotificationStackScrollLayout (int) height); } } - setMaxLayoutHeight(getHeight()); - updateContentHeight(); + if (!SceneContainerFlag.isEnabled()) { + setMaxLayoutHeight(getHeight()); + updateContentHeight(); + } clampScrollPosition(); requestChildrenUpdate(); updateFirstAndLastBackgroundViews(); @@ -1177,11 +1201,6 @@ public class NotificationStackScrollLayout } @Override - public void setStackHeightConsumer(@Nullable Consumer<Float> consumer) { - mScrollViewFields.setStackHeightConsumer(consumer); - } - - @Override public void setHeadsUpHeightConsumer(@Nullable Consumer<Float> consumer) { mScrollViewFields.setHeadsUpHeightConsumer(consumer); } @@ -2404,16 +2423,25 @@ public class NotificationStackScrollLayout /* notificationStackScrollLayout= */ this, mMaxDisplayedNotifications, shelfIntrinsicHeight); mIntrinsicContentHeight = height; - mScrollViewFields.sendStackHeight(height + footerIntrinsicHeight); // The topPadding can be bigger than the regular padding when qs is expanded, in that // state the maxPanelHeight and the contentHeight should be bigger mContentHeight = (int) (height + Math.max(mIntrinsicPadding, getTopPadding()) + mBottomPadding); + mScrollViewFields.setIntrinsicStackHeight( + (int) (mIntrinsicPadding + mIntrinsicContentHeight + footerIntrinsicHeight + + mBottomPadding)); updateScrollability(); clampScrollPosition(); updateStackPosition(); mAmbientState.setContentHeight(mContentHeight); + + notifyStackHeightChangedListeners(); + } + + @Override + public int getIntrinsicStackHeight() { + return mScrollViewFields.getIntrinsicStackHeight(); } /** @@ -3405,15 +3433,19 @@ public class NotificationStackScrollLayout int action = ev.getActionMasked(); boolean isUpOrCancel = action == ACTION_UP || action == ACTION_CANCEL; if (mSendingTouchesToSceneFramework) { - mController.sendTouchToSceneFramework(ev); + MotionEvent adjustedEvent = MotionEvent.obtain(ev); + adjustedEvent.setLocation(ev.getRawX(), ev.getRawY()); + mController.sendTouchToSceneFramework(adjustedEvent); mScrollViewFields.sendCurrentGestureOverscroll( getExpandedInThisMotion() && !isUpOrCancel); + adjustedEvent.recycle(); } else if (!isUpOrCancel) { // if this is the first touch being sent to the scene framework, // convert it into a synthetic DOWN event. mSendingTouchesToSceneFramework = true; MotionEvent downEvent = MotionEvent.obtain(ev); downEvent.setAction(MotionEvent.ACTION_DOWN); + downEvent.setLocation(ev.getRawX(), ev.getRawY()); mController.sendTouchToSceneFramework(downEvent); mScrollViewFields.sendCurrentGestureOverscroll(getExpandedInThisMotion()); downEvent.recycle(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt index 5bd4c758d678..a44674542b5c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt @@ -17,11 +17,9 @@ package com.android.systemui.statusbar.notification.stack import android.content.res.Resources -import android.os.SystemProperties import android.util.Log import android.view.View.GONE import androidx.annotation.VisibleForTesting -import com.android.systemui.Flags.notificationMinimalismPrototype import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.media.controls.domain.pipeline.MediaDataManager @@ -31,6 +29,7 @@ import com.android.systemui.statusbar.StatusBarState.KEYGUARD import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView +import com.android.systemui.statusbar.notification.shared.NotificationMinimalismPrototype import com.android.systemui.statusbar.policy.SplitShadeStateController import com.android.systemui.util.Compile import com.android.systemui.util.children @@ -381,16 +380,13 @@ constructor( fun updateResources() { maxKeyguardNotifications = infiniteIfNegative( - if (notificationMinimalismPrototype()) { - SystemProperties.getInt( - "persist.notification_minimalism_prototype.lock_screen_max_notifs", - 1 - ) + if (NotificationMinimalismPrototype.V1.isEnabled) { + NotificationMinimalismPrototype.V1.maxNotifs } else { resources.getInteger(R.integer.keyguard_max_notification_count) } ) - maxNotificationsExcludesMedia = notificationMinimalismPrototype() + maxNotificationsExcludesMedia = NotificationMinimalismPrototype.V1.isEnabled dividerHeight = max(1f, resources.getDimensionPixelSize(R.dimen.notification_divider_height).toFloat()) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt index a3827c140214..6afcf372b039 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt @@ -45,6 +45,12 @@ class ScrollViewFields { var isScrolledToTop: Boolean = true /** + * Height in view pixels at which the Notification Stack would like to be laid out, including + * Notification rows, paddings the Shelf and the Footer. + */ + var intrinsicStackHeight: Int = 0 + + /** * When internal NSSL expansion requires the stack to be scrolled (e.g. to keep an expanding * notification in view), that scroll amount can be sent here and it will be handled by the * placeholder @@ -56,11 +62,6 @@ class ScrollViewFields { */ var currentGestureOverscrollConsumer: Consumer<Boolean>? = null /** - * Any time the stack height is recalculated, it should be updated here to be used by the - * placeholder - */ - var stackHeightConsumer: Consumer<Float>? = null - /** * Any time the heads up height is recalculated, it should be updated here to be used by the * placeholder */ @@ -72,8 +73,6 @@ class ScrollViewFields { /** send [isCurrentGestureOverscroll] to the [currentGestureOverscrollConsumer], if present. */ fun sendCurrentGestureOverscroll(isCurrentGestureOverscroll: Boolean) = currentGestureOverscrollConsumer?.accept(isCurrentGestureOverscroll) - /** send the [stackHeight] to the [stackHeightConsumer], if present. */ - fun sendStackHeight(stackHeight: Float) = stackHeightConsumer?.accept(stackHeight) /** send the [headsUpHeight] to the [headsUpHeightConsumer], if present. */ fun sendHeadsUpHeight(headsUpHeight: Float) = headsUpHeightConsumer?.accept(headsUpHeight) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt index dacafc48fc72..db544ce59aa1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationPlaceholderRepository.kt @@ -38,16 +38,6 @@ class NotificationPlaceholderRepository @Inject constructor() { */ val shadeScrimBounds = MutableStateFlow<ShadeScrimBounds?>(null) - /** - * The y-coordinate in px of top of the contents of the notification stack. This value can be - * negative, if the stack is scrolled such that its top extends beyond the top edge of the - * screen. - */ - val stackTop = MutableStateFlow(0f) - - /** the bottom-most acceptable y-position for the bottom of the stack / shelf */ - val stackBottom = MutableStateFlow(0f) - /** the y position of the top of the HUN area */ val headsUpTop = MutableStateFlow(0f) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt index 920c9c213060..463c631db32f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationViewHeightRepository.kt @@ -27,13 +27,6 @@ import kotlinx.coroutines.flow.MutableStateFlow @SysUISingleton class NotificationViewHeightRepository @Inject constructor() { - /** - * The height in px of the contents of notification stack. Depending on the number of - * notifications, this can exceed the space available on screen to show notifications, at which - * point the notification stack should become scrollable. - */ - val stackHeight = MutableStateFlow(0f) - /** The height in px of the current heads up notification. */ val headsUpHeight = MutableStateFlow(0f) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt index b94da388cef4..e7acbe3ab0b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt @@ -65,13 +65,6 @@ constructor( } .distinctUntilChanged() - /** - * The height in px of the contents of notification stack. Depending on the number of - * notifications, this can exceed the space available on screen to show notifications, at which - * point the notification stack should become scrollable. - */ - val stackHeight: StateFlow<Float> = viewHeightRepository.stackHeight.asStateFlow() - /** The height in px of the contents of the HUN. */ val headsUpHeight: StateFlow<Float> = viewHeightRepository.headsUpHeight.asStateFlow() @@ -79,12 +72,6 @@ constructor( val alphaForBrightnessMirror: StateFlow<Float> = placeholderRepository.alphaForBrightnessMirror.asStateFlow() - /** The y-coordinate in px of top of the contents of the notification stack. */ - val stackTop: StateFlow<Float> = placeholderRepository.stackTop.asStateFlow() - - /** The y-coordinate in px of bottom of the contents of the notification stack. */ - val stackBottom: StateFlow<Float> = placeholderRepository.stackBottom.asStateFlow() - /** The height of the keyguard's available space bounds */ val constrainedAvailableSpace: StateFlow<Int> = placeholderRepository.constrainedAvailableSpace.asStateFlow() @@ -123,26 +110,11 @@ constructor( placeholderRepository.shadeScrimBounds.value = bounds } - /** Sets the height of the contents of the notification stack. */ - fun setStackHeight(height: Float) { - viewHeightRepository.stackHeight.value = height - } - /** Sets the height of heads up notification. */ fun setHeadsUpHeight(height: Float) { viewHeightRepository.headsUpHeight.value = height } - /** Sets the y-coord in px of the top of the contents of the notification stack. */ - fun setStackTop(stackTop: Float) { - placeholderRepository.stackTop.value = stackTop - } - - /** Sets the y-coord in px of the bottom of the contents of the notification stack. */ - fun setStackBottom(stackBottom: Float) { - placeholderRepository.stackBottom.value = stackBottom - } - /** Sets whether the notification stack is scrolled to the top. */ fun setScrolledToTop(scrolledToTop: Boolean) { placeholderRepository.scrolledToTop.value = scrolledToTop diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt index 2c8884504c32..14b882f974d2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt @@ -25,6 +25,13 @@ import java.util.function.Consumer * notification stack, but is otherwise agnostic to the content. */ interface NotificationScrollView { + + /** + * Height in view pixels at which the Notification Stack would like to be laid out, including + * Notification rows, paddings the Shelf and the Footer. + */ + val intrinsicStackHeight: Int + /** * Since this is an interface rather than a literal View, this provides cast-like access to the * underlying view. @@ -53,8 +60,6 @@ interface NotificationScrollView { fun setSyntheticScrollConsumer(consumer: Consumer<Float>?) /** Set a consumer for current gesture overscroll events */ fun setCurrentGestureOverscrollConsumer(consumer: Consumer<Boolean>?) - /** Set a consumer for stack height changed events */ - fun setStackHeightConsumer(consumer: Consumer<Float>?) /** Set a consumer for heads up height changed events */ fun setHeadsUpHeightConsumer(consumer: Consumer<Float>?) @@ -66,4 +71,10 @@ interface NotificationScrollView { /** Sets whether the view is displayed in doze mode. */ fun setDozing(dozing: Boolean) + + /** Sets a listener to be notified, when the stack height might have changed. */ + fun addStackHeightChangedListener(runnable: Runnable) + + /** @see addStackHeightChangedListener */ + fun removeStackHeightChangedListener(runnable: Runnable) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt index 26f7ad775f1d..622d8e7b2307 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationScrollViewBinder.kt @@ -79,8 +79,6 @@ constructor( } launch { viewModel.maxAlpha.collect { view.setMaxAlpha(it) } } - launch { viewModel.stackTop.collect { view.setStackTop(it) } } - launch { viewModel.stackBottom.collect { view.setStackBottom(it) } } launch { viewModel.scrolledToTop.collect { view.setScrolledToTop(it) } } launch { viewModel.headsUpTop.collect { view.setHeadsUpTop(it) } } launch { viewModel.expandFraction.collect { view.setExpandFraction(it.coerceIn(0f, 1f)) } } @@ -90,12 +88,10 @@ constructor( launchAndDispose { view.setSyntheticScrollConsumer(viewModel.syntheticScrollConsumer) view.setCurrentGestureOverscrollConsumer(viewModel.currentGestureOverscrollConsumer) - view.setStackHeightConsumer(viewModel.stackHeightConsumer) view.setHeadsUpHeightConsumer(viewModel.headsUpHeightConsumer) DisposableHandle { view.setSyntheticScrollConsumer(null) view.setCurrentGestureOverscrollConsumer(null) - view.setStackHeightConsumer(null) view.setHeadsUpHeightConsumer(null) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt index b2184db0879d..61373815db1c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationScrollViewModel.kt @@ -130,10 +130,6 @@ constructor( val maxAlpha: Flow<Float> = stackAppearanceInteractor.alphaForBrightnessMirror.dumpValue("maxAlpha") - /** The y-coordinate in px of top of the contents of the notification stack. */ - val stackTop: Flow<Float> = stackAppearanceInteractor.stackTop.dumpValue("stackTop") - /** The y-coordinate in px of bottom of the contents of the notification stack. */ - val stackBottom: Flow<Float> = stackAppearanceInteractor.stackBottom.dumpValue("stackBottom") /** * Whether the notification stack is scrolled to the top; i.e., it cannot be scrolled down any * further. @@ -151,8 +147,6 @@ constructor( */ val currentGestureOverscrollConsumer: (Boolean) -> Unit = stackAppearanceInteractor::setCurrentGestureOverscroll - /** Receives the height of the contents of the notification stack. */ - val stackHeightConsumer: (Float) -> Unit = stackAppearanceInteractor::setStackHeight /** Receives the height of the heads up notification. */ val headsUpHeightConsumer: (Float) -> Unit = stackAppearanceInteractor::setHeadsUpHeight diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt index 11eaf54efe47..97b86e3371f5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.stack.ui.viewmodel -import com.android.systemui.common.shared.model.NotificationContainerBounds import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.flags.FeatureFlagsClassic @@ -57,18 +56,6 @@ constructor( interactor.setShadeScrimBounds(bounds) } - /** Notifies that the bounds of the notification placeholder have changed. */ - fun onStackBoundsChanged( - top: Float, - bottom: Float, - ) { - keyguardInteractor.setNotificationContainerBounds( - NotificationContainerBounds(top = top, bottom = bottom) - ) - interactor.setStackTop(top) - interactor.setStackBottom(bottom) - } - /** Sets the available space */ fun onConstrainedAvailableSpaceChanged(height: Int) { interactor.setConstrainedAvailableSpace(height) @@ -87,13 +74,6 @@ constructor( val shadeScrimRounding: Flow<ShadeScrimRounding> = interactor.shadeScrimRounding.dumpWhileCollecting("shadeScrimRounding") - /** - * The height in px of the contents of notification stack. Depending on the number of - * notifications, this can exceed the space available on screen to show notifications, at which - * point the notification stack should become scrollable. - */ - val stackHeight: StateFlow<Float> = interactor.stackHeight.dumpValue("stackHeight") - /** The height in px of the contents of the HUN. */ val headsUpHeight: StateFlow<Float> = interactor.headsUpHeight.dumpValue("headsUpHeight") diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java index e93c0f6a5559..7dac77e91730 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java @@ -59,6 +59,7 @@ import com.android.systemui.shade.QuickSettingsController; import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeHeaderController; import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; +import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -82,6 +83,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba private final com.android.systemui.shade.ShadeController mShadeController; private final CommandQueue mCommandQueue; private final PanelExpansionInteractor mPanelExpansionInteractor; + private final Lazy<ShadeInteractor> mShadeInteractorLazy; private final ShadeHeaderController mShadeHeaderController; private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; private final MetricsLogger mMetricsLogger; @@ -121,6 +123,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba ShadeController shadeController, CommandQueue commandQueue, PanelExpansionInteractor panelExpansionInteractor, + Lazy<ShadeInteractor> shadeInteractorLazy, ShadeHeaderController shadeHeaderController, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, MetricsLogger metricsLogger, @@ -148,6 +151,7 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba mShadeController = shadeController; mCommandQueue = commandQueue; mPanelExpansionInteractor = panelExpansionInteractor; + mShadeInteractorLazy = shadeInteractorLazy; mShadeHeaderController = shadeHeaderController; mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler; mMetricsLogger = metricsLogger; @@ -487,14 +491,23 @@ public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callba } @Override - public void togglePanel() { - if (mPanelExpansionInteractor.isPanelExpanded()) { + public void toggleNotificationsPanel() { + if (mShadeInteractorLazy.get().isAnyExpanded().getValue()) { mShadeController.animateCollapseShade(); } else { mShadeController.animateExpandShade(); } } + @Override + public void toggleQuickSettingsPanel() { + if (mShadeInteractorLazy.get().isQsExpanded().getValue()) { + mShadeController.animateCollapseShade(); + } else { + mShadeController.animateExpandQs(); + } + } + private boolean isGoingToSleep() { return mWakefulnessLifecycle.getWakefulness() == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 23674b24d63e..aa55f375b2eb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import static android.app.StatusBarManager.DISABLE_HOME; import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN; import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; import static android.app.StatusBarManager.WindowVisibleState; @@ -1006,14 +1007,8 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // this handling this post-init task. We force an update in this case, and use a new // token to not conflict with any other disabled flags already requested by SysUI Binder token = new Binder(); - int userId = mContext.getUserId(); - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setNavigationHomeDisabled(true); - mBarService.disableForUser(info, token, mContext.getPackageName(), - userId, "set the initial view visibility"); - - mBarService.disableForUser(new StatusBarManager.DisableInfo(), token, - mContext.getPackageName(), userId, "set the initial view visibility"); + mBarService.disable(DISABLE_HOME, token, mContext.getPackageName()); + mBarService.disable(0, token, mContext.getPackageName()); } catch (RemoteException ex) { ex.rethrowFromSystemServer(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index f0dab3ba1829..b71564627223 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -696,6 +696,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb Trace.beginSection("StatusBarKeyguardViewManager#show"); mNotificationShadeWindowController.setKeyguardShowing(true); if (SceneContainerFlag.isEnabled()) { + // TODO(b/336581871): add sceneState? mSceneInteractorLazy.get().changeScene( Scenes.Lockscreen, "StatusBarKeyguardViewManager.show"); } diff --git a/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java b/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java new file mode 100644 index 000000000000..efeb2f919b56 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/theme/CustomDynamicColors.java @@ -0,0 +1,322 @@ +/* + * 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.theme; + +import com.google.ux.material.libmonet.dynamiccolor.ContrastCurve; +import com.google.ux.material.libmonet.dynamiccolor.DynamicColor; +import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors; +import com.google.ux.material.libmonet.dynamiccolor.ToneDeltaPair; +import com.google.ux.material.libmonet.dynamiccolor.TonePolarity; + +class CustomDynamicColors { + private final MaterialDynamicColors mMdc; + + CustomDynamicColors(boolean isExtendedFidelity) { + this.mMdc = new MaterialDynamicColors(isExtendedFidelity); + } + + // CLOCK COLORS + + public DynamicColor widgetBackground() { + return new DynamicColor( + /* name= */ "widget_background", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> s.isDark ? 20.0 : 95.0, + /* isBackground= */ true, + /* background= */ null, + /* secondBackground= */ null, + /* contrastCurve= */ null, + /* toneDeltaPair= */ null); + } + + public DynamicColor clockHour() { + return new DynamicColor( + /* name= */ "clock_hour", + /* palette= */ (s) -> s.secondaryPalette, + /* tone= */ (s) -> s.isDark ? 30.0 : 60.0, + /* isBackground= */ false, + /* background= */ (s) -> widgetBackground(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 4.0, 5.0, 15.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(clockHour(), clockMinute(), 10.0, TonePolarity.DARKER, + false)); + } + + public DynamicColor clockMinute() { + return new DynamicColor( + /* name= */ "clock_minute", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> s.isDark ? 40.0 : 90.0, + /* isBackground= */ false, + /* background= */ (s) -> widgetBackground(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 6.5, 10.0, 15.0), + /* toneDeltaPair= */ null); + } + + public DynamicColor clockSecond() { + return new DynamicColor( + /* name= */ "clock_second", + /* palette= */ (s) -> s.tertiaryPalette, + /* tone= */ (s) -> s.isDark ? 40.0 : 90.0, + /* isBackground= */ false, + /* background= */ (s) -> widgetBackground(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 5.0, 70.0, 11.0), + /* toneDeltaPair= */ null); + } + + public DynamicColor weatherTemp() { + return new DynamicColor( + /* name= */ "clock_second", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> s.isDark ? 55.0 : 80.0, + /* isBackground= */ false, + /* background= */ (s) -> widgetBackground(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 5.0, 70.0, 11.0), + /* toneDeltaPair= */ null); + } + + // THEME APP ICONS + + public DynamicColor themeApp() { + return new DynamicColor( + /* name= */ "theme_app", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> s.isDark ? 90.0 : 30.0, // Adjusted values + /* isBackground= */ true, + /* background= */ null, + /* secondBackground= */ null, + /* contrastCurve= */ null, + /* toneDeltaPair= */ null); + } + + public DynamicColor onThemeApp() { + return new DynamicColor( + /* name= */ "on_theme_app", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> s.isDark ? 40.0 : 80.0, // Adjusted values + /* isBackground= */ false, + /* background= */ (s) -> themeApp(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 7.0, 10.0), + /* toneDeltaPair= */ null); + } + + public DynamicColor themeAppRing() { + return new DynamicColor( + /* name= */ "theme_app_ring", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> 70.0, + /* isBackground= */ true, + /* background= */ null, + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0), + /* toneDeltaPair= */ null); + } + + public DynamicColor themeNotif() { + return new DynamicColor( + /* name= */ "theme_notif", + /* palette= */ (s) -> s.tertiaryPalette, + /* tone= */ (s) -> s.isDark ? 80.0 : 90.0, + /* isBackground= */ false, + /* background= */ (s) -> themeAppRing(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(themeNotif(), themeAppRing(), 10.0, TonePolarity.NEARER, + false)); + } + + // SUPER G COLORS + + public DynamicColor brandA() { + return new DynamicColor( + /* name= */ "brand_a", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> s.isDark ? 40.0 : 80.0, + /* isBackground= */ true, + /* background= */ (s) -> mMdc.surfaceContainerLow(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 7.0, 17.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(brandA(), brandB(), 10.0, TonePolarity.NEARER, false)); + } + + public DynamicColor brandB() { + return new DynamicColor( + /* name= */ "brand_b", + /* palette= */ (s) -> s.secondaryPalette, + /* tone= */ (s) -> s.isDark ? 70.0 : 98.0, + /* isBackground= */ true, + /* background= */ (s) -> mMdc.surfaceContainerLow(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 3.0, 6.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(brandB(), brandC(), 10.0, TonePolarity.NEARER, false)); + } + + public DynamicColor brandC() { + return new DynamicColor( + /* name= */ "brand_c", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> s.isDark ? 50.0 : 60.0, + /* isBackground= */ false, + /* background= */ (s) -> mMdc.surfaceContainerLow(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.0, 9.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(brandC(), brandD(), 10.0, TonePolarity.NEARER, false)); + } + + public DynamicColor brandD() { + return new DynamicColor( + /* name= */ "brand_d", + /* palette= */ (s) -> s.tertiaryPalette, + /* tone= */ (s) -> s.isDark ? 59.0 : 90.0, + /* isBackground= */ false, + /* background= */ (s) -> mMdc.surfaceContainerLow(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.0, 13.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(brandD(), brandA(), 10.0, TonePolarity.NEARER, false)); + } + + // QUICK SETTING TIILES + + public DynamicColor underSurface() { + return new DynamicColor( + /* name= */ "under_surface", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> 0.0, + /* isBackground= */ true, + /* background= */ null, + /* secondBackground= */ null, + /* contrastCurve= */ null, + /* toneDeltaPair= */ null); + } + + public DynamicColor shadeActive() { + return new DynamicColor( + /* name= */ "shade_active", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> 90.0, + /* isBackground= */ false, + /* background= */ (s) -> underSurface(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 3.0, 4.5, 7.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(shadeActive(), shadeInactive(), 30.0, TonePolarity.LIGHTER, + false)); + } + + public DynamicColor onShadeActive() { + return new DynamicColor( + /* name= */ "on_shade_active", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> 10.0, + /* isBackground= */ false, + /* background= */ (s) -> shadeActive(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(onShadeActive(), onShadeActiveVariant(), 20.0, + TonePolarity.NEARER, false)); + } + + public DynamicColor onShadeActiveVariant() { + return new DynamicColor( + /* name= */ "on_shade_active_variant", + /* palette= */ (s) -> s.primaryPalette, + /* tone= */ (s) -> 30.0, + /* isBackground= */ false, + /* background= */ (s) -> shadeActive(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(onShadeActiveVariant(), onShadeActive(), 20.0, + TonePolarity.NEARER, false)); + } + + public DynamicColor shadeInactive() { + return new DynamicColor( + /* name= */ "shade_inactive", + /* palette= */ (s) -> s.neutralPalette, + /* tone= */ (s) -> 20.0, + /* isBackground= */ true, + /* background= */ (s) -> underSurface(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0), + /* toneDeltaPair= */(s) -> new ToneDeltaPair(shadeInactive(), shadeDisabled(), 15.0, + TonePolarity.LIGHTER, false)); + } + + public DynamicColor onShadeInactive() { + return new DynamicColor( + /* name= */ "on_shade_inactive", + /* palette= */ (s) -> s.neutralVariantPalette, + /* tone= */ (s) -> 90.0, + /* isBackground= */ true, + /* background= */ (s) -> shadeInactive(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(onShadeInactive(), onShadeInactiveVariant(), 10.0, + TonePolarity.NEARER, false)); + } + + public DynamicColor onShadeInactiveVariant() { + return new DynamicColor( + /* name= */ "on_shade_inactive_variant", + /* palette= */ (s) -> s.neutralVariantPalette, + /* tone= */ (s) -> 80.0, + /* isBackground= */ false, + /* background= */ (s) -> shadeInactive(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 4.5, 7.0, 11.0), + /* toneDeltaPair= */ + (s) -> new ToneDeltaPair(onShadeInactiveVariant(), onShadeInactive(), 10.0, + TonePolarity.NEARER, false)); + } + + public DynamicColor shadeDisabled() { + return new DynamicColor( + /* name= */ "shade_disabled", + /* palette= */ (s) -> s.neutralPalette, + /* tone= */ (s) -> 4.0, + /* isBackground= */ false, + /* background= */ (s) -> underSurface(), + /* secondBackground= */ null, + /* contrastCurve= */ new ContrastCurve(1.0, 1.0, 1.0, 1.0), + /* toneDeltaPair= */ null); + } + + public DynamicColor overviewBackground() { + return new DynamicColor( + /* name= */ "overview_background", + /* palette= */ (s) -> s.neutralVariantPalette, + /* tone= */ (s) -> s.isDark ? 80.0 : 35.0, + /* isBackground= */ true, + /* background= */ null, + /* secondBackground= */ null, + /* contrastCurve= */null, + /* toneDeltaPair= */ null); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt index a983d2f9b78e..35187597bd83 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt +++ b/packages/SystemUI/src/com/android/systemui/theme/DynamicColors.kt @@ -103,5 +103,33 @@ class DynamicColors { Pair.create("on_tertiary_fixed_variant", mdc.onTertiaryFixedVariant()), ) } + + @JvmStatic + fun getCustomColorsMapped(isExtendedFidelity: Boolean): List<Pair<String, DynamicColor>> { + val customMdc = CustomDynamicColors(isExtendedFidelity) + return arrayListOf( + Pair.create("widget_background", customMdc.widgetBackground()), + Pair.create("clock_hour", customMdc.clockHour()), + Pair.create("clock_minute", customMdc.clockMinute()), + Pair.create("clock_second", customMdc.weatherTemp()), + Pair.create("theme_app", customMdc.themeApp()), + Pair.create("on_theme_app", customMdc.onThemeApp()), + Pair.create("theme_app_ring", customMdc.themeAppRing()), + Pair.create("on_theme_app_ring", customMdc.themeNotif()), + Pair.create("brand_a", customMdc.brandA()), + Pair.create("brand_b", customMdc.brandB()), + Pair.create("brand_c", customMdc.brandC()), + Pair.create("brand_d", customMdc.brandD()), + Pair.create("under_surface", customMdc.underSurface()), + Pair.create("shade_active", customMdc.shadeActive()), + Pair.create("on_shade_active", customMdc.onShadeActive()), + Pair.create("on_shade_active_variant", customMdc.onShadeActiveVariant()), + Pair.create("shade_inactive", customMdc.shadeInactive()), + Pair.create("on_shade_inactive", customMdc.onShadeInactive()), + Pair.create("on_shade_inactive_variant", customMdc.onShadeInactiveVariant()), + Pair.create("shade_disabled", customMdc.shadeDisabled()), + Pair.create("overview_background", customMdc.overviewBackground()) + ) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java index 5c3bbb7ca253..d256c4acd955 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java @@ -56,6 +56,7 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; +import android.util.Pair; import android.util.SparseArray; import android.util.SparseIntArray; @@ -84,6 +85,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceP import com.android.systemui.util.kotlin.JavaAdapter; import com.android.systemui.util.settings.SecureSettings; +import com.google.ux.material.libmonet.dynamiccolor.DynamicColor; import com.google.ux.material.libmonet.dynamiccolor.MaterialDynamicColors; import org.json.JSONException; @@ -631,29 +633,33 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { protected FabricatedOverlay createDynamicOverlay() { FabricatedOverlay overlay = newFabricatedOverlay("dynamic"); - assignDynamicPaletteToOverlay(overlay, true /* isDark */); - assignDynamicPaletteToOverlay(overlay, false /* isDark */); - assignFixedColorsToOverlay(overlay); + //Themed Colors + assignColorsToOverlay(overlay, DynamicColors.allDynamicColorsMapped(mIsFidelityEnabled), + false); + // Fixed Colors + assignColorsToOverlay(overlay, DynamicColors.getFixedColorsMapped(mIsFidelityEnabled), + true); + //Custom Colors + assignColorsToOverlay(overlay, DynamicColors.getCustomColorsMapped(mIsFidelityEnabled), + false); return overlay; } - private void assignDynamicPaletteToOverlay(FabricatedOverlay overlay, boolean isDark) { - String suffix = isDark ? "dark" : "light"; - ColorScheme scheme = isDark ? mDarkColorScheme : mLightColorScheme; - DynamicColors.allDynamicColorsMapped(mIsFidelityEnabled).forEach(p -> { - String resourceName = "android:color/system_" + p.first + "_" + suffix; - int colorValue = p.second.getArgb(scheme.getMaterialScheme()); - overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue, - null /* configuration */); - }); - } + private void assignColorsToOverlay(FabricatedOverlay overlay, + List<Pair<String, DynamicColor>> colors, Boolean isFixed) { + colors.forEach(p -> { + String prefix = "android:color/system_" + p.first; - private void assignFixedColorsToOverlay(FabricatedOverlay overlay) { - DynamicColors.getFixedColorsMapped(mIsFidelityEnabled).forEach(p -> { - String resourceName = "android:color/system_" + p.first; - int colorValue = p.second.getArgb(mLightColorScheme.getMaterialScheme()); - overlay.setResourceValue(resourceName, TYPE_INT_COLOR_ARGB8, colorValue, - null /* configuration */); + if (isFixed) { + overlay.setResourceValue(prefix, TYPE_INT_COLOR_ARGB8, + p.second.getArgb(mLightColorScheme.getMaterialScheme()), null); + return; + } + + overlay.setResourceValue(prefix + "_light", TYPE_INT_COLOR_ARGB8, + p.second.getArgb(mLightColorScheme.getMaterialScheme()), null); + overlay.setResourceValue(prefix + "_dark", TYPE_INT_COLOR_ARGB8, + p.second.getArgb(mDarkColorScheme.getMaterialScheme()), null); }); } diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt index 46ce5f2623de..1ec86a4d1dfc 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/JavaAdapter.kt @@ -97,3 +97,12 @@ fun <T> collectFlow( fun <A, B, R> combineFlows(flow1: Flow<A>, flow2: Flow<B>, bifunction: (A, B) -> R): Flow<R> { return combine(flow1, flow2, bifunction) } + +fun <A, B, C, R> combineFlows( + flow1: Flow<A>, + flow2: Flow<B>, + flow3: Flow<C>, + trifunction: (A, B, C) -> R +): Flow<R> { + return combine(flow1, flow2, flow3, trifunction) +} diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SharedPreferencesExt.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SharedPreferencesExt.kt index ab6a37bccc11..d9e19d83cbf4 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SharedPreferencesExt.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SharedPreferencesExt.kt @@ -17,23 +17,15 @@ package com.android.systemui.util.kotlin import android.content.SharedPreferences -import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow +import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.mapNotNull object SharedPreferencesExt { - /** - * Returns a flow of [Unit] that is invoked each time shared preference is updated. - * - * @param key Optional key to limit updates to a particular key. - */ - fun SharedPreferences.observe(key: String? = null): Flow<Unit> = - conflatedCallbackFlow { - val listener = - SharedPreferences.OnSharedPreferenceChangeListener { _, key -> trySend(key) } - registerOnSharedPreferenceChangeListener(listener) - awaitClose { unregisterOnSharedPreferenceChangeListener(listener) } - } - .mapNotNull { changedKey -> if ((key ?: changedKey) == changedKey) Unit else null } + /** Returns a flow of [Unit] that is invoked each time shared preference is updated. */ + fun SharedPreferences.observe(): Flow<Unit> = conflatedCallbackFlow { + val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, _ -> trySend(Unit) } + registerOnSharedPreferenceChangeListener(listener) + awaitClose { unregisterOnSharedPreferenceChangeListener(listener) } + } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java index c69fb662b67d..e56893a36a57 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java @@ -174,9 +174,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private static final String TYPE_DISMISS = "dismiss"; /** Volume dialog slider animation. */ private static final String TYPE_UPDATE = "update"; - static final int PROGRESS_HAPTICS_DISABLED = 0; - static final int PROGRESS_HAPTICS_EAGER = 1; - static final int PROGRESS_HAPTICS_ANIMATED = 2; /** * TODO(b/290612381): remove lingering animations or tolerate them @@ -285,7 +282,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, @GuardedBy("mSafetyWarningLock") private CsdWarningDialog mCsdDialog; private boolean mHovering = false; - private final boolean mShowActiveStreamOnly; + private final boolean mIsTv; private boolean mConfigChanged = false; private boolean mIsAnimatingDismiss = false; private boolean mHasSeenODICaptionsTooltip; @@ -346,7 +343,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, mConfigurationController = configurationController; mMediaOutputDialogManager = mediaOutputDialogManager; mCsdWarningDialogFactory = csdWarningDialogFactory; - mShowActiveStreamOnly = showActiveStreamOnly(); + mIsTv = isTv(); mHasSeenODICaptionsTooltip = Prefs.getBoolean(context, Prefs.Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP, false); mShowLowMediaVolumeIcon = @@ -1635,7 +1632,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, Trace.endSection(); } - private boolean showActiveStreamOnly() { + private boolean isTv() { return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK) || mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEVISION); } @@ -1647,7 +1644,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, return true; } - if (!mShowActiveStreamOnly) { + if (!mIsTv) { if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) { return mShowA11yStream; } @@ -2092,6 +2089,11 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, } final int newProgress = getProgressFromVolume(row.ss, row.slider, vlevel); if (progress != newProgress) { + if (mIsTv) { + // don't animate slider on TVs + row.slider.setProgress(newProgress, false); + return; + } if (mShowing && rowVisible) { // animate! if (row.anim != null && row.anim.isRunning() @@ -2112,7 +2114,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, row.anim.setIntValues(progress, newProgress); // The animator can't keep up with the volume changes so haptics need to be // triggered here. This happens when the volume keys are continuously pressed. - row.deliverOnProgressChangedHaptics(false, newProgress, PROGRESS_HAPTICS_EAGER); + row.deliverOnProgressChangedHaptics(false, newProgress); } row.animTargetProgress = newProgress; row.anim.setDuration(UPDATE_ANIMATION_DURATION); @@ -2127,13 +2129,14 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, } } - @VisibleForTesting int progressHapticsForStream(int stream) { + @VisibleForTesting + boolean canDeliverProgressHapticsToStream(int stream, boolean fromUser, int progress) { for (VolumeRow row: mRows) { if (row.stream == stream) { - return row.mProgressHapticsType; + return row.deliverOnProgressChangedHaptics(fromUser, progress); } } - return PROGRESS_HAPTICS_DISABLED; + return false; } private void recheckH(VolumeRow row) { @@ -2527,8 +2530,7 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, if (fromUser || mRow.animTargetProgress == progress) { // Deliver user-generated slider haptics immediately, or when the animation // completes - mRow.deliverOnProgressChangedHaptics( - fromUser, progress, PROGRESS_HAPTICS_ANIMATED); + mRow.deliverOnProgressChangedHaptics(fromUser, progress); } } if (D.BUG) Log.d(TAG, AudioSystem.streamToString(mRow.stream) @@ -2641,7 +2643,6 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, private int animTargetProgress; private int lastAudibleLevel = 1; private SeekbarHapticPlugin mHapticPlugin; - private int mProgressHapticsType = PROGRESS_HAPTICS_DISABLED; void setIcon(int iconRes, Resources.Theme theme) { if (icon != null) { @@ -2683,15 +2684,23 @@ public class VolumeDialogImpl implements VolumeDialog, Dumpable, slider.setOnTouchListener(null); } - void deliverOnProgressChangedHaptics(boolean fromUser, int progress, int hapticsType) { - if (mHapticPlugin == null) return; + /** + * Deliver haptics when the progress of the slider has changed. + * + * @param fromUser True if the progress changed was caused by the user. + * @param progress The progress value of the slider. + * @return True if haptics were successfully delivered. False otherwise. This will happen + * if mHapticPlugin is null + */ + boolean deliverOnProgressChangedHaptics(boolean fromUser, int progress) { + if (mHapticPlugin == null) return false; mHapticPlugin.onProgressChanged(slider, progress, fromUser); if (!fromUser) { // Consider a change from program as the volume key being continuously pressed mHapticPlugin.onKeyDown(); } - mProgressHapticsType = hapticsType; + return true; } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt index 26d6a9a0153d..4b4d69a31db4 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/AudioVolumeComponentViewModel.kt @@ -31,13 +31,15 @@ import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.transformLatest import kotlinx.coroutines.launch @@ -53,12 +55,39 @@ class AudioVolumeComponentViewModel constructor( @VolumePanelScope private val scope: CoroutineScope, mediaOutputInteractor: MediaOutputInteractor, - private val mediaDeviceSessionInteractor: MediaDeviceSessionInteractor, + mediaDeviceSessionInteractor: MediaDeviceSessionInteractor, private val streamSliderViewModelFactory: AudioStreamSliderViewModel.Factory, private val castVolumeSliderViewModelFactory: CastVolumeSliderViewModel.Factory, streamsInteractor: AudioSlidersInteractor, ) { + private val mutableIsExpanded = MutableStateFlow<Boolean?>(null) + private val isPlaybackActive: Flow<Boolean?> = + mediaOutputInteractor.defaultActiveMediaSession + .filterData() + .flatMapLatest { session -> + if (session == null) { + flowOf(false) + } else { + mediaDeviceSessionInteractor.playbackState(session).map { it?.isActive == true } + } + } + .onEach { isPlaybackActive -> mutableIsExpanded.value = !isPlaybackActive } + .stateIn(scope, SharingStarted.Eagerly, null) + private val portraitExpandable: Flow<SlidersExpandableViewModel> = + isPlaybackActive + .filterNotNull() + .flatMapLatest { isActive -> + if (isActive) { + mutableIsExpanded.filterNotNull().map { isExpanded -> + SlidersExpandableViewModel.Expandable(isExpanded) + } + } else { + flowOf(SlidersExpandableViewModel.Fixed) + } + } + .stateIn(scope, SharingStarted.Eagerly, SlidersExpandableViewModel.Unavailable) + val sliderViewModels: StateFlow<List<SliderViewModel>> = streamsInteractor.volumePanelSliders .transformLatest { sliderTypes -> @@ -76,24 +105,16 @@ constructor( } .stateIn(scope, SharingStarted.Eagerly, emptyList()) - private val mutableIsExpanded = MutableSharedFlow<Boolean>() - - val isExpanded: StateFlow<Boolean> = - merge( - mutableIsExpanded, - mediaOutputInteractor.defaultActiveMediaSession.filterData().flatMapLatest { session - -> - if (session == null) flowOf(true) - else - mediaDeviceSessionInteractor.playbackState(session).map { - it?.isActive != true - } - }, - ) - .stateIn(scope, SharingStarted.Eagerly, false) + fun isExpandable(isPortrait: Boolean): Flow<SlidersExpandableViewModel> { + return if (isPortrait) { + portraitExpandable + } else { + flowOf(SlidersExpandableViewModel.Fixed) + } + } fun onExpandedChanged(isExpanded: Boolean) { - scope.launch { mutableIsExpanded.emit(isExpanded) } + scope.launch { mutableIsExpanded.value = isExpanded } } private fun CoroutineScope.createSessionViewModel( diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/SlidersExpandableViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/SlidersExpandableViewModel.kt new file mode 100644 index 000000000000..19b9ead88ebb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/SlidersExpandableViewModel.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.volume.ui.viewmodel + +/** + * Models expandability state of the + * [com.android.systemui.volume.panel.component.volume.ui.composable.VolumeSlidersComponent]. + */ +sealed interface SlidersExpandableViewModel { + + /** [SlidersExpandableViewModel] is not loaded. */ + data object Unavailable : SlidersExpandableViewModel + + data class Expandable(val isExpanded: Boolean) : SlidersExpandableViewModel + + data object Fixed : SlidersExpandableViewModel +} diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java index b86a7c92ba47..e073f7cde826 100644 --- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java +++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java @@ -98,7 +98,7 @@ public final class WMShell implements CoreStartable, CommandQueue.Callbacks { private static final String TAG = WMShell.class.getName(); - private static final int INVALID_SYSUI_STATE_MASK = + private static final long INVALID_SYSUI_STATE_MASK = SYSUI_STATE_DIALOG_SHOWING | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java index 6dc5b7212cd0..bbdd8050a142 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationTest.java @@ -27,6 +27,7 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_M import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doAnswer; @@ -104,7 +105,7 @@ public class MagnificationTest extends SysuiTestCase { }).when(mAccessibilityManager).setMagnificationConnection( any(IMagnificationConnection.class)); - when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState); + when(mSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mSysUiState); doAnswer(invocation -> { mMagnification.mMagnificationSettingsControllerCallback diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt index bf6ca0684398..e371b39faab4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogDelegateTest.kt @@ -46,12 +46,12 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyLong import org.mockito.Mock import org.mockito.Mockito.spy import org.mockito.Mockito.verify -import org.mockito.Mockito.`when` as whenever import org.mockito.MockitoAnnotations +import org.mockito.Mockito.`when` as whenever private const val ON: Int = 1 private const val OFF: Int = 0 @@ -90,7 +90,7 @@ class FontScalingDialogDelegateTest : SysuiTestCase() { secureSettings = FakeSettings() systemClock = FakeSystemClock() backgroundDelayableExecutor = FakeExecutor(systemClock) - whenever(sysuiState.setFlag(anyInt(), anyBoolean())).thenReturn(sysuiState) + whenever(sysuiState.setFlag(anyLong(), anyBoolean())).thenReturn(sysuiState) fontScalingDialogDelegate = spy( diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java index ebb6b48f9532..8895a5e1a97c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegateTest.java @@ -23,6 +23,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -118,7 +119,7 @@ public class HearingDevicesDialogDelegateTest extends SysuiTestCase { when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager); when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mDevices); when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager); - when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState); + when(mSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mSysUiState); when(mCachedDevice.getAddress()).thenReturn(DEVICE_ADDRESS); when(mHearingDeviceItem.getCachedBluetoothDevice()).thenReturn(mCachedDevice); diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt index 8e4c155593e2..fd37cad72371 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt @@ -8,6 +8,7 @@ import android.content.pm.ApplicationInfo import android.graphics.Point import android.graphics.Rect import android.os.Looper +import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.IRemoteAnimationFinishedCallback @@ -17,15 +18,20 @@ import android.view.SurfaceControl import android.view.ViewGroup import android.widget.FrameLayout import android.widget.LinearLayout +import android.window.RemoteTransition +import android.window.TransitionFilter import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.shared.Flags import com.android.systemui.util.mockito.any +import com.android.wm.shell.shared.ShellTransitions import junit.framework.Assert.assertFalse import junit.framework.Assert.assertNotNull import junit.framework.Assert.assertNull import junit.framework.Assert.assertTrue import junit.framework.AssertionFailedError import kotlin.concurrent.thread +import kotlin.test.assertEquals import org.junit.After import org.junit.Assert.assertThrows import org.junit.Before @@ -48,6 +54,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { private val transitionContainer = LinearLayout(mContext) private val mainExecutor = context.mainExecutor private val testTransitionAnimator = fakeTransitionAnimator(mainExecutor) + private val testShellTransitions = FakeShellTransitions() @Mock lateinit var callback: ActivityTransitionAnimator.Callback @Mock lateinit var listener: ActivityTransitionAnimator.Listener @Spy private val controller = TestTransitionAnimatorController(transitionContainer) @@ -55,12 +62,16 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { private lateinit var activityTransitionAnimator: ActivityTransitionAnimator @get:Rule val rule = MockitoJUnit.rule() + @get:Rule val setFlagsRule = SetFlagsRule() @Before fun setup() { activityTransitionAnimator = ActivityTransitionAnimator( mainExecutor, + ActivityTransitionAnimator.TransitionRegister.fromShellTransitions( + testShellTransitions + ), testTransitionAnimator, testTransitionAnimator, disableWmTimeout = true, @@ -164,6 +175,34 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { } @Test + fun registersReturnIffCookieIsPresent() { + setFlagsRule.enableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY) + `when`(callback.isOnKeyguard()).thenReturn(false) + + startIntentWithAnimation(activityTransitionAnimator, controller) { _ -> + ActivityManager.START_DELIVERED_TO_TOP + } + + waitForIdleSync() + assertTrue(testShellTransitions.remotes.isEmpty()) + assertTrue(testShellTransitions.remotesForTakeover.isEmpty()) + + val controller = + object : DelegateTransitionAnimatorController(controller) { + override val transitionCookie + get() = ActivityTransitionAnimator.TransitionCookie("testCookie") + } + + startIntentWithAnimation(activityTransitionAnimator, controller) { _ -> + ActivityManager.START_DELIVERED_TO_TOP + } + + waitForIdleSync() + assertEquals(1, testShellTransitions.remotes.size) + assertTrue(testShellTransitions.remotesForTakeover.isEmpty()) + } + + @Test fun doesNotStartIfAnimationIsCancelled() { val runner = activityTransitionAnimator.createRunner(controller) runner.onAnimationCancelled() @@ -243,6 +282,35 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { } /** + * A fake implementation of [ShellTransitions] which saves filter-transition pairs locally and + * allows inspection. + */ +private class FakeShellTransitions : ShellTransitions { + val remotes = mutableMapOf<TransitionFilter, RemoteTransition>() + val remotesForTakeover = mutableMapOf<TransitionFilter, RemoteTransition>() + + override fun registerRemote(filter: TransitionFilter, remoteTransition: RemoteTransition) { + remotes[filter] = remoteTransition + } + + override fun registerRemoteForTakeover( + filter: TransitionFilter, + remoteTransition: RemoteTransition + ) { + remotesForTakeover[filter] = remoteTransition + } + + override fun unregisterRemote(remoteTransition: RemoteTransition) { + while (remotes.containsValue(remoteTransition)) { + remotes.values.remove(remoteTransition) + } + while (remotesForTakeover.containsValue(remoteTransition)) { + remotesForTakeover.values.remove(remoteTransition) + } + } +} + +/** * A simple implementation of [ActivityTransitionAnimator.Controller] which throws if it is called * outside of the main thread. */ diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt index b31fe21f8e91..42fcd547408a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/GhostedViewTransitionAnimatorControllerTest.kt @@ -16,12 +16,16 @@ package com.android.systemui.animation +import android.os.HandlerThread import android.testing.AndroidTestingRunner import android.testing.TestableLooper +import android.view.View import android.widget.FrameLayout import androidx.test.filters.SmallTest +import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.SysuiTestCase import com.android.systemui.animation.view.LaunchableFrameLayout +import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertThrows import org.junit.Test import org.junit.runner.RunWith @@ -30,6 +34,13 @@ import org.junit.runner.RunWith @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper class GhostedViewTransitionAnimatorControllerTest : SysuiTestCase() { + companion object { + private const val LAUNCH_CUJ = 0 + private const val RETURN_CUJ = 1 + } + + private val interactionJankMonitor = FakeInteractionJankMonitor() + @Test fun animatingOrphanViewDoesNotCrash() { val state = TransitionAnimator.State(top = 0, bottom = 0, left = 0, right = 0) @@ -47,4 +58,63 @@ class GhostedViewTransitionAnimatorControllerTest : SysuiTestCase() { GhostedViewTransitionAnimatorController(FrameLayout(mContext)) } } + + @Test + fun cujsAreLoggedCorrectly() { + val parent = FrameLayout(mContext) + + val launchView = LaunchableFrameLayout(mContext) + parent.addView((launchView)) + val launchController = + GhostedViewTransitionAnimatorController( + launchView, + launchCujType = LAUNCH_CUJ, + returnCujType = RETURN_CUJ, + interactionJankMonitor = interactionJankMonitor + ) + launchController.onTransitionAnimationStart(isExpandingFullyAbove = true) + assertThat(interactionJankMonitor.ongoing).containsExactly(LAUNCH_CUJ) + launchController.onTransitionAnimationEnd(isExpandingFullyAbove = true) + assertThat(interactionJankMonitor.ongoing).isEmpty() + assertThat(interactionJankMonitor.finished).containsExactly(LAUNCH_CUJ) + + val returnView = LaunchableFrameLayout(mContext) + parent.addView((returnView)) + val returnController = + object : GhostedViewTransitionAnimatorController( + returnView, + launchCujType = LAUNCH_CUJ, + returnCujType = RETURN_CUJ, + interactionJankMonitor = interactionJankMonitor + ) { + override val isLaunching = false + } + returnController.onTransitionAnimationStart(isExpandingFullyAbove = true) + assertThat(interactionJankMonitor.ongoing).containsExactly(RETURN_CUJ) + returnController.onTransitionAnimationEnd(isExpandingFullyAbove = true) + assertThat(interactionJankMonitor.ongoing).isEmpty() + assertThat(interactionJankMonitor.finished).containsExactly(LAUNCH_CUJ, RETURN_CUJ) + } + + /** + * A fake implementation of [InteractionJankMonitor] which stores ongoing and finished CUJs and + * allows inspection. + */ + private class FakeInteractionJankMonitor : InteractionJankMonitor( + HandlerThread("testThread") + ) { + val ongoing: MutableSet<Int> = mutableSetOf() + val finished: MutableSet<Int> = mutableSetOf() + + override fun begin(v: View?, cujType: Int): Boolean { + ongoing.add(cujType) + return true + } + + override fun end(cujType: Int): Boolean { + ongoing.remove(cujType) + finished.add(cujType) + return true + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt index de3b741b762c..e81369d9631c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt @@ -43,6 +43,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.internal.jank.InteractionJankMonitor import com.android.internal.widget.LockPatternUtils +import com.android.launcher3.icons.IconProvider import com.android.systemui.Flags.FLAG_CONSTRAINT_BP import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.data.repository.FakeBiometricStatusRepository @@ -150,6 +151,7 @@ open class AuthContainerViewTest : SysuiTestCase() { private lateinit var displayStateInteractor: DisplayStateInteractor private lateinit var udfpsOverlayInteractor: UdfpsOverlayInteractor private lateinit var biometricStatusInteractor: BiometricStatusInteractor + private lateinit var iconProvider: IconProvider private val credentialViewModel = CredentialViewModel(mContext, bpCredentialInteractor) private val defaultLogoIcon = context.getDrawable(R.drawable.ic_android) @@ -178,6 +180,7 @@ open class AuthContainerViewTest : SysuiTestCase() { biometricStatusInteractor = BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository, fingerprintRepository) + iconProvider = IconProvider(context) // Set up default logo icon whenever(packageManager.getApplicationIcon(OP_PACKAGE_NAME)).thenReturn(defaultLogoIcon) context.setMockPackageManager(packageManager) @@ -649,14 +652,15 @@ open class AuthContainerViewTest : SysuiTestCase() { lockPatternUtils, interactionJankMonitor, { promptSelectorInteractor }, - { bpCredentialInteractor }, PromptViewModel( displayStateInteractor, promptSelectorInteractor, context, udfpsOverlayInteractor, biometricStatusInteractor, - udfpsUtils + udfpsUtils, + iconProvider, + activityTaskManager ), { credentialViewModel }, Handler(TestableLooper.get(this).looper), diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt index df0e5a718ed9..5e4272f125d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/data/repository/PromptRepositoryImplTest.kt @@ -16,13 +16,8 @@ package com.android.systemui.biometrics.data.repository -import android.hardware.biometrics.BiometricManager -import android.hardware.biometrics.Flags.FLAG_CUSTOM_BIOMETRIC_PROMPT -import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton import android.hardware.biometrics.PromptInfo -import android.hardware.biometrics.PromptVerticalListContentView import androidx.test.filters.SmallTest -import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.biometrics.AuthController import com.android.systemui.biometrics.shared.model.PromptKind @@ -139,83 +134,6 @@ class PromptRepositoryImplTest : SysuiTestCase() { } @Test - fun showBpWithoutIconForCredential_withVerticalListContentView() = - testScope.runTest { - mSetFlagsRule.enableFlags(Flags.FLAG_CONSTRAINT_BP) - mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) - for (case in - listOf( - PromptKind.Biometric(), - PromptKind.Pin, - PromptKind.Password, - PromptKind.Pattern - )) { - val hasCredentialViewShown = case !is PromptKind.Biometric - val promptInfo = - PromptInfo().apply { - authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL - contentView = PromptVerticalListContentView.Builder().build() - } - repository.setPrompt(promptInfo, USER_ID, CHALLENGE, case, OP_PACKAGE_NAME) - repository.setShouldShowBpWithoutIconForCredential(promptInfo) - - assertThat(repository.showBpWithoutIconForCredential.value) - .isEqualTo(!hasCredentialViewShown) - } - } - - @Test - fun showBpWithoutIconForCredential_withContentViewWithMoreOptionsButton() = - testScope.runTest { - mSetFlagsRule.enableFlags(Flags.FLAG_CONSTRAINT_BP) - mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) - val promptInfo = - PromptInfo().apply { - authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL - contentView = - PromptContentViewWithMoreOptionsButton.Builder() - .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> } - .build() - } - for (case in - listOf( - PromptKind.Biometric(), - PromptKind.Pin, - PromptKind.Password, - PromptKind.Pattern - )) { - repository.setPrompt(promptInfo, USER_ID, CHALLENGE, case, OP_PACKAGE_NAME) - repository.setShouldShowBpWithoutIconForCredential(promptInfo) - - assertThat(repository.showBpWithoutIconForCredential.value).isFalse() - } - } - - @Test - fun showBpWithoutIconForCredential_withDescription() = - testScope.runTest { - mSetFlagsRule.enableFlags(Flags.FLAG_CONSTRAINT_BP) - mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) - for (case in - listOf( - PromptKind.Biometric(), - PromptKind.Pin, - PromptKind.Password, - PromptKind.Pattern - )) { - val promptInfo = - PromptInfo().apply { - authenticators = BiometricManager.Authenticators.DEVICE_CREDENTIAL - description = "description" - } - repository.setPrompt(promptInfo, USER_ID, CHALLENGE, case, OP_PACKAGE_NAME) - repository.setShouldShowBpWithoutIconForCredential(promptInfo) - - assertThat(repository.showBpWithoutIconForCredential.value).isFalse() - } - } - - @Test fun setsAndUnsetsPrompt() = testScope.runTest { val kind = PromptKind.Pin @@ -223,7 +141,7 @@ class PromptRepositoryImplTest : SysuiTestCase() { repository.setPrompt(promptInfo, USER_ID, CHALLENGE, kind, OP_PACKAGE_NAME) - assertThat(repository.kind.value).isEqualTo(kind) + assertThat(repository.promptKind.value).isEqualTo(kind) assertThat(repository.userId.value).isEqualTo(USER_ID) assertThat(repository.challenge.value).isEqualTo(CHALLENGE) assertThat(repository.promptInfo.value).isSameInstanceAs(promptInfo) diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt index c308507fdd90..4068404da29f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/PromptSelectorInteractorImplTest.kt @@ -17,8 +17,11 @@ package com.android.systemui.biometrics.domain.interactor import android.app.admin.DevicePolicyManager +import android.content.ComponentName import android.hardware.biometrics.BiometricManager.Authenticators +import android.hardware.biometrics.PromptContentViewWithMoreOptionsButton import android.hardware.biometrics.PromptInfo +import android.hardware.biometrics.PromptVerticalListContentView import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils import com.android.systemui.SysuiTestCase @@ -29,8 +32,10 @@ import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal import com.android.systemui.biometrics.shared.model.BiometricModalities import com.android.systemui.biometrics.shared.model.PromptKind import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.whenever +import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope @@ -43,19 +48,22 @@ import org.junit.runners.JUnit4 import org.mockito.Mock import org.mockito.junit.MockitoJUnit -private const val TITLE = "hey there" -private const val SUBTITLE = "ok" -private const val DESCRIPTION = "football" -private const val NEGATIVE_TEXT = "escape" - -private const val USER_ID = 8 -private const val CHALLENGE = 999L -private const val OP_PACKAGE_NAME = "biometric.testapp" - @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(JUnit4::class) class PromptSelectorInteractorImplTest : SysuiTestCase() { + companion object { + private const val TITLE = "hey there" + private const val SUBTITLE = "ok" + private const val DESCRIPTION = "football" + private const val NEGATIVE_TEXT = "escape" + + private const val USER_ID = 8 + private const val CHALLENGE = 999L + private const val OP_PACKAGE_NAME = "biometric.testapp" + private val componentNameOverriddenForConfirmDeviceCredentialActivity = + ComponentName("not.com.android.settings", "testapp") + } @JvmField @Rule var mockitoRule = MockitoJUnit.rule() @@ -64,6 +72,7 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { private val testScope = TestScope() private val fingerprintRepository = FakeFingerprintPropertyRepository() private val promptRepository = FakePromptRepository() + private val fakeExecutor = FakeExecutor(FakeSystemClock()) private lateinit var interactor: PromptSelectorInteractor @@ -73,6 +82,23 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils) } + private fun basicPromptInfo() = + PromptInfo().apply { + title = TITLE + subtitle = SUBTITLE + description = DESCRIPTION + negativeButtonText = NEGATIVE_TEXT + isConfirmationRequested = true + isDeviceCredentialAllowed = true + authenticators = Authenticators.BIOMETRIC_STRONG or Authenticators.DEVICE_CREDENTIAL + } + + private val modalities = + BiometricModalities( + fingerprintProperties = fingerprintSensorPropertiesInternal().first(), + faceProperties = faceSensorPropertiesInternal().first(), + ) + @Test fun useBiometricsAndReset() = testScope.runTest { useBiometricsAndReset(allowCredentialFallback = true) } @@ -81,16 +107,24 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { fun useBiometricsAndResetWithoutFallback() = testScope.runTest { useBiometricsAndReset(allowCredentialFallback = false) } - private fun TestScope.useBiometricsAndReset(allowCredentialFallback: Boolean) { + @Test + fun useBiometricsAndResetOnConfirmDeviceCredentialActivity() = + testScope.runTest { + useBiometricsAndReset( + allowCredentialFallback = true, + setComponentNameForConfirmDeviceCredentialActivity = true + ) + } + + private fun TestScope.useBiometricsAndReset( + allowCredentialFallback: Boolean, + setComponentNameForConfirmDeviceCredentialActivity: Boolean = false + ) { setUserCredentialType(isPassword = true) val confirmationRequired = true val info = - PromptInfo().apply { - title = TITLE - subtitle = SUBTITLE - description = DESCRIPTION - negativeButtonText = NEGATIVE_TEXT + basicPromptInfo().apply { isConfirmationRequested = confirmationRequired authenticators = if (allowCredentialFallback) { @@ -99,26 +133,27 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { Authenticators.BIOMETRIC_STRONG } isDeviceCredentialAllowed = allowCredentialFallback + componentNameForConfirmDeviceCredentialActivity = + if (setComponentNameForConfirmDeviceCredentialActivity) + componentNameOverriddenForConfirmDeviceCredentialActivity + else null } - val modalities = - BiometricModalities( - fingerprintProperties = fingerprintSensorPropertiesInternal().first(), - faceProperties = faceSensorPropertiesInternal().first(), - ) val currentPrompt by collectLastValue(interactor.prompt) - val credentialKind by collectLastValue(interactor.credentialKind) + val promptKind by collectLastValue(interactor.promptKind) val isCredentialAllowed by collectLastValue(interactor.isCredentialAllowed) - val isExplicitConfirmationRequired by collectLastValue(interactor.isConfirmationRequired) + val credentialKind by collectLastValue(interactor.credentialKind) + val isConfirmationRequired by collectLastValue(interactor.isConfirmationRequired) assertThat(currentPrompt).isNull() - interactor.useBiometricsForAuthentication( + interactor.setPrompt( info, USER_ID, - CHALLENGE, modalities, - OP_PACKAGE_NAME + CHALLENGE, + OP_PACKAGE_NAME, + false /*onSwitchToCredential*/ ) assertThat(currentPrompt).isNotNull() @@ -127,15 +162,22 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { assertThat(currentPrompt?.subtitle).isEqualTo(SUBTITLE) assertThat(currentPrompt?.negativeButtonText).isEqualTo(NEGATIVE_TEXT) assertThat(currentPrompt?.opPackageName).isEqualTo(OP_PACKAGE_NAME) + assertThat(promptKind!!.isBiometric()).isTrue() + assertThat(currentPrompt?.componentNameForConfirmDeviceCredentialActivity) + .isEqualTo( + if (setComponentNameForConfirmDeviceCredentialActivity) + componentNameOverriddenForConfirmDeviceCredentialActivity + else null + ) if (allowCredentialFallback) { assertThat(credentialKind).isSameInstanceAs(PromptKind.Password) assertThat(isCredentialAllowed).isTrue() } else { - assertThat(credentialKind).isEqualTo(PromptKind.Biometric()) + assertThat(credentialKind).isEqualTo(PromptKind.None) assertThat(isCredentialAllowed).isFalse() } - assertThat(isExplicitConfirmationRequired).isEqualTo(confirmationRequired) + assertThat(isConfirmationRequired).isEqualTo(confirmationRequired) interactor.resetPrompt() verifyUnset() @@ -152,6 +194,143 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { fun usePasswordCredentialAndReset() = testScope.runTest { useCredentialAndReset(PromptKind.Password) } + @Test + fun promptKind_isBiometric_whenBiometricAllowed() = + testScope.runTest { + setUserCredentialType(isPassword = true) + val info = basicPromptInfo() + + val promptKind by collectLastValue(interactor.promptKind) + assertThat(promptKind).isEqualTo(PromptKind.None) + + interactor.setPrompt( + info, + USER_ID, + modalities, + CHALLENGE, + OP_PACKAGE_NAME, + false /*onSwitchToCredential*/ + ) + + assertThat(promptKind?.isBiometric()).isTrue() + + interactor.resetPrompt() + verifyUnset() + } + + @Test + fun promptKind_isCredential_onSwitchToCredential() = + testScope.runTest { + setUserCredentialType(isPassword = true) + val info = basicPromptInfo() + + val promptKind by collectLastValue(interactor.promptKind) + assertThat(promptKind).isEqualTo(PromptKind.None) + + interactor.setPrompt( + info, + USER_ID, + modalities, + CHALLENGE, + OP_PACKAGE_NAME, + true /*onSwitchToCredential*/ + ) + + assertThat(promptKind).isEqualTo(PromptKind.Password) + + interactor.resetPrompt() + verifyUnset() + } + + @Test + fun promptKind_isCredential_whenBiometricIsNotAllowed() = + testScope.runTest { + setUserCredentialType(isPassword = true) + val info = + basicPromptInfo().apply { + isDeviceCredentialAllowed = true + authenticators = Authenticators.DEVICE_CREDENTIAL + } + + val promptKind by collectLastValue(interactor.promptKind) + assertThat(promptKind).isEqualTo(PromptKind.None) + + interactor.setPrompt( + info, + USER_ID, + modalities, + CHALLENGE, + OP_PACKAGE_NAME, + false /*onSwitchToCredential*/ + ) + + assertThat(promptKind).isEqualTo(PromptKind.Password) + + interactor.resetPrompt() + verifyUnset() + } + + @Test + fun promptKind_isCredential_whenBiometricIsNotAllowed_withMoreOptionsButton() = + testScope.runTest { + setUserCredentialType(isPassword = true) + val info = + basicPromptInfo().apply { + isDeviceCredentialAllowed = true + authenticators = Authenticators.DEVICE_CREDENTIAL + contentView = + PromptContentViewWithMoreOptionsButton.Builder() + .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> } + .build() + } + + val promptKind by collectLastValue(interactor.promptKind) + assertThat(promptKind).isEqualTo(PromptKind.None) + + interactor.setPrompt( + info, + USER_ID, + modalities, + CHALLENGE, + OP_PACKAGE_NAME, + false /*onSwitchToCredential*/ + ) + + assertThat(promptKind).isEqualTo(PromptKind.Password) + + interactor.resetPrompt() + verifyUnset() + } + + @Test + fun promptKind_isBiometric_whenBiometricIsNotAllowed_withVerticalList() = + testScope.runTest { + setUserCredentialType(isPassword = true) + val info = + basicPromptInfo().apply { + isDeviceCredentialAllowed = true + authenticators = Authenticators.DEVICE_CREDENTIAL + contentView = PromptVerticalListContentView.Builder().build() + } + + val promptKind by collectLastValue(interactor.promptKind) + assertThat(promptKind).isEqualTo(PromptKind.None) + + interactor.setPrompt( + info, + USER_ID, + modalities, + CHALLENGE, + OP_PACKAGE_NAME, + false /*onSwitchToCredential*/ + ) + + assertThat(promptKind?.isBiometric()).isTrue() + + interactor.resetPrompt() + verifyUnset() + } + private fun TestScope.useCredentialAndReset(kind: PromptKind) { setUserCredentialType( isPin = kind == PromptKind.Pin, @@ -173,11 +352,18 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { assertThat(currentPrompt).isNull() - interactor.useCredentialsForAuthentication(info, kind, USER_ID, CHALLENGE, OP_PACKAGE_NAME) + interactor.setPrompt( + info, + USER_ID, + BiometricModalities(), + CHALLENGE, + OP_PACKAGE_NAME, + false /*onSwitchToCredential*/ + ) // not using biometrics, should be null with no fallback option assertThat(currentPrompt).isNull() - assertThat(credentialKind).isEqualTo(PromptKind.Biometric()) + assertThat(credentialKind).isEqualTo(PromptKind.None) interactor.resetPrompt() verifyUnset() @@ -185,13 +371,16 @@ class PromptSelectorInteractorImplTest : SysuiTestCase() { private fun TestScope.verifyUnset() { val currentPrompt by collectLastValue(interactor.prompt) + val promptKind by collectLastValue(interactor.promptKind) + val isCredentialAllowed by collectLastValue(interactor.isCredentialAllowed) val credentialKind by collectLastValue(interactor.credentialKind) + val isConfirmationRequired by collectLastValue(interactor.isConfirmationRequired) assertThat(currentPrompt).isNull() - - val kind = credentialKind as? PromptKind.Biometric - assertThat(kind).isNotNull() - assertThat(kind?.activeModalities?.isEmpty).isTrue() + assertThat(promptKind).isEqualTo(PromptKind.None) + assertThat(isCredentialAllowed).isFalse() + assertThat(credentialKind).isEqualTo(PromptKind.None) + assertThat(isConfirmationRequired).isFalse() } private fun setUserCredentialType(isPin: Boolean = false, isPassword: Boolean = false) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt index a7324182a91a..97c3c4264855 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt @@ -16,9 +16,13 @@ package com.android.systemui.biometrics.ui.viewmodel +import android.app.ActivityManager.RunningTaskInfo import android.app.ActivityTaskManager +import android.content.ComponentName +import android.content.pm.ActivityInfo import android.content.pm.ApplicationInfo import android.content.pm.PackageManager +import android.content.pm.PackageManager.NameNotFoundException import android.content.res.Configuration import android.graphics.Bitmap import android.graphics.Point @@ -37,6 +41,7 @@ import android.view.HapticFeedbackConstants import android.view.MotionEvent import androidx.test.filters.SmallTest import com.android.internal.widget.LockPatternUtils +import com.android.launcher3.icons.IconProvider import com.android.systemui.Flags.FLAG_BP_TALKBACK import com.android.systemui.Flags.FLAG_CONSTRAINT_BP import com.android.systemui.SysuiTestCase @@ -94,6 +99,7 @@ private const val CHALLENGE = 2L private const val DELAY = 1000L private const val OP_PACKAGE_NAME = "biometric.testapp" private const val OP_PACKAGE_NAME_NO_ICON = "biometric.testapp.noicon" +private const val OP_PACKAGE_NAME_CAN_NOT_BE_FOUND = "can.not.be.found" @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @@ -107,18 +113,23 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa @Mock private lateinit var selectedUserInteractor: SelectedUserInteractor @Mock private lateinit var udfpsUtils: UdfpsUtils @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var iconProvider: IconProvider @Mock private lateinit var applicationInfoWithIcon: ApplicationInfo @Mock private lateinit var applicationInfoNoIcon: ApplicationInfo @Mock private lateinit var activityTaskManager: ActivityTaskManager + @Mock private lateinit var activityInfo: ActivityInfo + @Mock private lateinit var runningTaskInfo: RunningTaskInfo private val fakeExecutor = FakeExecutor(FakeSystemClock()) private val testScope = TestScope() private val defaultLogoIcon = context.getDrawable(R.drawable.ic_android) + private val defaultLogoIconWithOverrides = context.getDrawable(R.drawable.ic_add) private val logoResFromApp = R.drawable.ic_cake private val logoFromApp = context.getDrawable(logoResFromApp) private val logoBitmapFromApp = Bitmap.createBitmap(400, 400, Bitmap.Config.RGB_565) private val defaultLogoDescription = "Test Android App" private val logoDescriptionFromApp = "Test Cake App" + private val packageNameForLogoWithOverrides = "should.use.overridden.logo" private lateinit var fingerprintRepository: FakeFingerprintPropertyRepository private lateinit var promptRepository: FakePromptRepository @@ -169,11 +180,12 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa ) biometricStatusRepository = FakeBiometricStatusRepository() biometricStatusInteractor = - BiometricStatusInteractorImpl(activityTaskManager, biometricStatusRepository, - fingerprintRepository) - selector = - PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils) - selector.resetPrompt() + BiometricStatusInteractorImpl( + activityTaskManager, + biometricStatusRepository, + fingerprintRepository + ) + promptContentView = PromptVerticalListContentView.Builder() .addListItem(PromptContentItemBulletedText("content item 1")) @@ -183,32 +195,35 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa promptContentViewWithMoreOptionsButton = PromptContentViewWithMoreOptionsButton.Builder() .setDescription("test") - .setMoreOptionsButtonListener(fakeExecutor, { _, _ -> }) + .setMoreOptionsButtonListener(fakeExecutor) { _, _ -> } .build() - viewModel = - PromptViewModel( - displayStateInteractor, - selector, - mContext, - udfpsOverlayInteractor, - biometricStatusInteractor, - udfpsUtils - ) - iconViewModel = viewModel.iconViewModel - - // Set up default logo icon and app customized icon + // Set up default logo info and app customized info whenever(packageManager.getApplicationInfo(eq(OP_PACKAGE_NAME_NO_ICON), anyInt())) .thenReturn(applicationInfoNoIcon) whenever(packageManager.getApplicationInfo(eq(OP_PACKAGE_NAME), anyInt())) .thenReturn(applicationInfoWithIcon) + whenever(packageManager.getApplicationInfo(eq(packageNameForLogoWithOverrides), anyInt())) + .thenReturn(applicationInfoWithIcon) + whenever(packageManager.getApplicationInfo(eq(OP_PACKAGE_NAME_CAN_NOT_BE_FOUND), anyInt())) + .thenThrow(NameNotFoundException()) + + whenever(packageManager.getActivityInfo(any(), anyInt())).thenReturn(activityInfo) + whenever(iconProvider.getIcon(activityInfo)).thenReturn(defaultLogoIconWithOverrides) whenever(packageManager.getApplicationIcon(applicationInfoWithIcon)) .thenReturn(defaultLogoIcon) whenever(packageManager.getApplicationLabel(applicationInfoWithIcon)) .thenReturn(defaultLogoDescription) + whenever(packageManager.getUserBadgedIcon(any(), any())).then { it.getArgument(0) } + whenever(packageManager.getUserBadgedLabel(any(), any())).then { it.getArgument(0) } + context.setMockPackageManager(packageManager) val resources = context.getOrCreateTestableResources() resources.addOverride(logoResFromApp, logoFromApp) + resources.addOverride( + R.array.biometric_dialog_package_names_for_logo_with_overrides, + arrayOf(packageNameForLogoWithOverrides) + ) } @Test @@ -1319,7 +1334,30 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - fun logoIsNullIfPackageNameNotFound() = + fun logo_nullIfPkgNameNotFound() = + runGenericTest(packageName = OP_PACKAGE_NAME_CAN_NOT_BE_FOUND) { + mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) + mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) + val logo by collectLastValue(viewModel.logo) + assertThat(logo).isNull() + } + + @Test + fun logo_defaultWithOverrides() = + runGenericTest(packageName = packageNameForLogoWithOverrides) { + mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) + mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) + val logo by collectLastValue(viewModel.logo) + + // 1. PM.getApplicationInfo(packageNameForLogoWithOverrides) is set to return + // applicationInfoWithIcon with defaultLogoIcon, + // 2. iconProvider.getIcon() is set to return defaultLogoIconForGMSCore + // For the apps with packageNameForLogoWithOverrides, 2 should be called instead of 1 + assertThat(logo).isEqualTo(defaultLogoIconWithOverrides) + } + + @Test + fun logo_defaultIsNull() = runGenericTest(packageName = OP_PACKAGE_NAME_NO_ICON) { mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) @@ -1328,7 +1366,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - fun defaultLogoIfNoLogoSet() = runGenericTest { + fun logo_default() = runGenericTest { mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) val logo by collectLastValue(viewModel.logo) @@ -1336,7 +1374,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - fun logoResSetByApp() = + fun logo_resSetByApp() = runGenericTest(logoRes = logoResFromApp) { mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) @@ -1345,7 +1383,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - fun logoBitmapSetByApp() = + fun logo_bitmapSetByApp() = runGenericTest(logoBitmap = logoBitmapFromApp) { mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) @@ -1354,7 +1392,16 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - fun logoDescriptionIsEmptyIfPackageNameNotFound() = + fun logoDescription_emptyIfPkgNameNotFound() = + runGenericTest(packageName = OP_PACKAGE_NAME_CAN_NOT_BE_FOUND) { + mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) + mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) + val logoDescription by collectLastValue(viewModel.logoDescription) + assertThat(logoDescription).isEqualTo("") + } + + @Test + fun logoDescription_defaultIsEmpty() = runGenericTest(packageName = OP_PACKAGE_NAME_NO_ICON) { mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) @@ -1363,7 +1410,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - fun defaultLogoDescriptionIfNoLogoDescriptionSet() = runGenericTest { + fun logoDescription_default() = runGenericTest { mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) val logoDescription by collectLastValue(viewModel.logoDescription) @@ -1371,7 +1418,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa } @Test - fun logoDescriptionSetByApp() = + fun logoDescription_setByApp() = runGenericTest(logoDescription = logoDescriptionFromApp) { mSetFlagsRule.enableFlags(FLAG_CUSTOM_BIOMETRIC_PROMPT) mSetFlagsRule.enableFlags(FLAG_CONSTRAINT_BP) @@ -1417,6 +1464,26 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa packageName: String = OP_PACKAGE_NAME, block: suspend TestScope.() -> Unit, ) { + val topActivity = ComponentName(packageName, "test app") + runningTaskInfo.topActivity = topActivity + whenever(activityTaskManager.getTasks(1)).thenReturn(listOf(runningTaskInfo)) + selector = + PromptSelectorInteractorImpl(fingerprintRepository, promptRepository, lockPatternUtils) + selector.resetPrompt() + + viewModel = + PromptViewModel( + displayStateInteractor, + selector, + mContext, + udfpsOverlayInteractor, + biometricStatusInteractor, + udfpsUtils, + iconProvider, + activityTaskManager + ) + iconViewModel = viewModel.iconViewModel + selector.initializePrompt( requireConfirmation = testCase.confirmationRequested, allowCredentialFallback = allowCredentialFallback, @@ -1630,12 +1697,13 @@ private fun PromptSelectorInteractor.initializePrompt( isConfirmationRequested = requireConfirmation } - useBiometricsForAuthentication( + setPrompt( info, USER_ID, - CHALLENGE, BiometricModalities(fingerprintProperties = fingerprint, faceProperties = face), + CHALLENGE, packageName, + false /*onUseDeviceCredential*/ ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java index a569ceec32b2..49f204372730 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/BroadcastDialogDelegateTest.java @@ -21,7 +21,7 @@ import static com.android.systemui.statusbar.phone.SystemUIDialog.DEFAULT_DISMIS import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -92,7 +92,7 @@ public class BroadcastDialogDelegateTest extends SysuiTestCase { when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager); when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(null); - when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState); + when(mSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mSysUiState); when(mSystemUIDialogFactory.create(any(), any())).thenReturn(mDialog); mBroadcastDialogDelegate = new BroadcastDialogDelegate( diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt index 62c98b05cbd5..72156194b0e1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogDelegateTest.kt @@ -50,7 +50,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyLong import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.junit.MockitoJUnit @@ -104,7 +104,7 @@ class BluetoothTileDialogDelegateTest : SysuiTestCase() { dispatcher = UnconfinedTestDispatcher(scheduler) testScope = TestScope(dispatcher) - whenever(sysuiState.setFlag(anyInt(), anyBoolean())).thenReturn(sysuiState) + whenever(sysuiState.setFlag(anyLong(), anyBoolean())).thenReturn(sysuiState) mBluetoothTileDialogDelegate = BluetoothTileDialogDelegate( diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java index bc6c459881be..5361cef2ac64 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/FalsingCollectorImplTest.java @@ -35,9 +35,13 @@ import androidx.test.filters.SmallTest; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.SysuiTestCase; import com.android.systemui.communal.domain.interactor.CommunalInteractor; +import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerFake; +import com.android.systemui.flags.DisableSceneContainer; +import com.android.systemui.flags.EnableSceneContainer; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor; import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; @@ -50,6 +54,7 @@ import com.android.systemui.util.sensors.ProximitySensor; import com.android.systemui.util.sensors.ThresholdSensor; import com.android.systemui.util.time.FakeSystemClock; +import kotlinx.coroutines.flow.MutableStateFlow; import kotlinx.coroutines.flow.StateFlowKt; import org.junit.Before; @@ -89,6 +94,14 @@ public class FalsingCollectorImplTest extends SysuiTestCase { private SelectedUserInteractor mSelectedUserInteractor; @Mock private CommunalInteractor mCommunalInteractor; + @Mock + private DeviceEntryInteractor mDeviceEntryInteractor; + private final MutableStateFlow<Boolean> mIsDeviceEntered = + StateFlowKt.MutableStateFlow(false); + @Mock + private SceneContainerOcclusionInteractor mSceneContainerOcclusionInteractor; + private final MutableStateFlow<Boolean> mIsInvisibleDueToOcclusion = + StateFlowKt.MutableStateFlow(false); private final DockManagerFake mDockManager = new DockManagerFake(); private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); private final FakeExecutor mFakeExecutor = new FakeExecutor(mFakeSystemClock); @@ -99,15 +112,21 @@ public class FalsingCollectorImplTest extends SysuiTestCase { when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD); when(mKeyguardStateController.isShowing()).thenReturn(true); + when(mKeyguardStateController.isOccluded()).thenReturn(false); when(mShadeInteractor.isQsExpanded()).thenReturn(StateFlowKt.MutableStateFlow(false)); + when(mDeviceEntryInteractor.isDeviceEntered()).thenReturn(mIsDeviceEntered); + when(mSceneContainerOcclusionInteractor.getInvisibleDueToOcclusion()).thenReturn( + mIsInvisibleDueToOcclusion); + mFalsingCollector = new FalsingCollectorImpl(mFalsingDataProvider, mFalsingManager, mKeyguardUpdateMonitor, mHistoryTracker, mProximitySensor, mStatusBarStateController, mKeyguardStateController, () -> mShadeInteractor, mBatteryController, mDockManager, mFakeExecutor, mJavaAdapter, mFakeSystemClock, () -> mSelectedUserInteractor, - () -> mCommunalInteractor + () -> mCommunalInteractor, () -> mDeviceEntryInteractor, + () -> mSceneContainerOcclusionInteractor ); mFalsingCollector.init(); } @@ -189,7 +208,8 @@ public class FalsingCollectorImplTest extends SysuiTestCase { } @Test - public void testRegisterSensor_OccludingActivity() { + @DisableSceneContainer + public void testRegisterSensor_OccludingActivity_sceneContainerDisabled() { when(mKeyguardStateController.isOccluded()).thenReturn(true); ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor = @@ -203,6 +223,21 @@ public class FalsingCollectorImplTest extends SysuiTestCase { } @Test + @EnableSceneContainer + public void testRegisterSensor_OccludingActivity_sceneContainerEnabled() { + mIsInvisibleDueToOcclusion.setValue(true); + + ArgumentCaptor<StatusBarStateController.StateListener> stateListenerArgumentCaptor = + ArgumentCaptor.forClass(StatusBarStateController.StateListener.class); + verify(mStatusBarStateController).addCallback(stateListenerArgumentCaptor.capture()); + + mFalsingCollector.onScreenTurningOn(); + reset(mProximitySensor); + stateListenerArgumentCaptor.getValue().onStateChanged(StatusBarState.SHADE); + verify(mProximitySensor).register(any(ThresholdSensor.Listener.class)); + } + + @Test public void testPassThroughEnterKeyEvent() { KeyEvent enterDown = KeyEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0, 0, 0, 0, ""); @@ -280,7 +315,8 @@ public class FalsingCollectorImplTest extends SysuiTestCase { } @Test - public void testAvoidUnlocked() { + @DisableSceneContainer + public void testAvoidUnlocked_sceneContainerDisabled() { MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0); @@ -296,6 +332,23 @@ public class FalsingCollectorImplTest extends SysuiTestCase { } @Test + @EnableSceneContainer + public void testAvoidUnlocked_sceneContainerEnabled() { + MotionEvent down = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0); + MotionEvent up = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0); + + mIsDeviceEntered.setValue(true); + + // Nothing passed initially + mFalsingCollector.onTouchEvent(down); + verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); + + // Up event would normally flush the up event, but doesn't. + mFalsingCollector.onTouchEvent(up); + verify(mFalsingDataProvider, never()).onMotionEvent(any(MotionEvent.class)); + } + + @Test public void testGestureWhenDozing() { // We check the FalsingManager for taps during the transition to AoD (dozing=true, // pulsing=false), so the FalsingCollector needs to continue to analyze events that occur diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt index c3a806ba8d43..ef15d21107b0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt @@ -32,6 +32,7 @@ import com.android.systemui.communal.domain.interactor.setCommunalAvailable import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.dock.fakeDockManager import com.android.systemui.flags.BrokenWithSceneContainer +import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.andSceneContainer import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository @@ -157,6 +158,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun lockscreenToPrimaryBouncerViaBouncerShowingCall() = testScope.runTest { // GIVEN a prior transition has run to LOCKSCREEN @@ -370,6 +372,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun dreamingLockscreenHostedToGone() = testScope.runTest { // GIVEN a prior transition has run to DREAMING_LOCKSCREEN_HOSTED @@ -396,6 +399,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun dreamingLockscreenHostedToPrimaryBouncer() = testScope.runTest { // GIVEN a device dreaming with lockscreen hosted dream and not dozing @@ -623,6 +627,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest /** This handles security method NONE and screen off with lock timeout */ @Test + @DisableSceneContainer fun dreamingToGoneWithKeyguardNotShowing() = testScope.runTest { // GIVEN a prior transition has run to DREAMING @@ -679,6 +684,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun goneToDozing() = testScope.runTest { // GIVEN a device with AOD not available @@ -704,6 +710,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun goneToAod() = testScope.runTest { // GIVEN a device with AOD available @@ -751,6 +758,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun goneToDreaming() = testScope.runTest { // GIVEN a device that is not dreaming or dozing @@ -809,6 +817,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun alternateBouncerToPrimaryBouncer() = testScope.runTest { // GIVEN a prior transition has run to ALTERNATE_BOUNCER @@ -985,6 +994,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun primaryBouncerToAod() = testScope.runTest { // GIVEN aod available @@ -1015,6 +1025,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun primaryBouncerToDozing() = testScope.runTest { // GIVEN a prior transition has run to PRIMARY_BOUNCER @@ -1043,6 +1054,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun primaryBouncerToLockscreen() = testScope.runTest { // GIVEN a prior transition has run to PRIMARY_BOUNCER @@ -1066,6 +1078,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun primaryBouncerToGlanceableHub() = testScope.runTest { // GIVEN a prior transition has run to PRIMARY_BOUNCER @@ -1097,6 +1110,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun primaryBouncerToGlanceableHubWhileDreaming() = testScope.runTest { // GIVEN a prior transition has run to PRIMARY_BOUNCER @@ -1132,6 +1146,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun primaryBouncerToDreamingLockscreenHosted() = testScope.runTest { // GIVEN device dreaming with the lockscreen hosted dream and not dozing @@ -1445,7 +1460,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest keyguardRepository.setKeyguardOccluded(false) runCurrent() - // THEN a transition to GLANCEABLE_HUB should occur + // THEN a transition to DREAMING should occur assertThat(transitionRepository) .startedTransition( ownerName = FromOccludedTransitionInteractor::class.simpleName, @@ -1511,6 +1526,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun dreamingToGlanceableHub() = testScope.runTest { // GIVEN a prior transition has run to DREAMING @@ -1598,6 +1614,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun aodToPrimaryBouncer() = testScope.runTest { // GIVEN a prior transition has run to AOD @@ -1699,6 +1716,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun lockscreenToGlanceableHub() = testScope.runTest { // GIVEN a prior transition has run to LOCKSCREEN @@ -1756,6 +1774,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun glanceableHubToLockscreen() = testScope.runTest { // GIVEN a prior transition has run to GLANCEABLE_HUB @@ -1810,6 +1829,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun glanceableHubToDozing() = testScope.runTest { // GIVEN a prior transition has run to GLANCEABLE_HUB @@ -1831,6 +1851,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun glanceableHubToPrimaryBouncer() = testScope.runTest { // GIVEN a prior transition has run to ALTERNATE_BOUNCER @@ -1852,6 +1873,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun glanceableHubToAlternateBouncer() = testScope.runTest { // GIVEN a prior transition has run to ALTERNATE_BOUNCER @@ -1904,6 +1926,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun glanceableHubToGone() = testScope.runTest { // GIVEN a prior transition has run to GLANCEABLE_HUB @@ -1925,6 +1948,7 @@ class KeyguardTransitionScenariosTest(flags: FlagsParameterization?) : SysuiTest } @Test + @DisableSceneContainer fun glanceableHubToDreaming() = testScope.runTest { // GIVEN that we are dreaming and not dozing diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt index b1a8dd1d3fdc..a77169e74de5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorTest.kt @@ -18,20 +18,29 @@ package com.android.systemui.keyguard.domain.interactor import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues +import com.android.systemui.flags.DisableSceneContainer +import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState import com.android.systemui.keyguard.shared.model.TransitionStep import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.data.repository.sceneContainerRepository +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertEquals import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -57,14 +66,22 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { .thenReturn(surfaceBehindIsAnimatingFlow) } - private val underTest = kosmos.windowManagerLockscreenVisibilityInteractor + private val underTest = lazy { kosmos.windowManagerLockscreenVisibilityInteractor } private val testScope = kosmos.testScope private val transitionRepository = kosmos.fakeKeyguardTransitionRepository + @Before + fun setUp() { + // lazy value needs to be called here otherwise flow collection misbehaves + underTest.value + kosmos.sceneContainerRepository.setTransitionState(sceneTransitions) + } + @Test + @DisableSceneContainer fun surfaceBehindVisibility_switchesToCorrectFlow() = testScope.runTest { - val values by collectValues(underTest.surfaceBehindVisibility) + val values by collectValues(underTest.value.surfaceBehindVisibility) // Start on LOCKSCREEN. transitionRepository.sendTransitionStep( @@ -170,9 +187,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { } @Test + @DisableSceneContainer fun testUsingGoingAwayAnimation_duringTransitionToGone() = testScope.runTest { - val values by collectValues(underTest.usingKeyguardGoingAwayAnimation) + val values by collectValues(underTest.value.usingKeyguardGoingAwayAnimation) // Start on LOCKSCREEN. transitionRepository.sendTransitionStep( @@ -230,9 +248,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { } @Test + @DisableSceneContainer fun testNotUsingGoingAwayAnimation_evenWhenAnimating_ifStateIsNotGone() = testScope.runTest { - val values by collectValues(underTest.usingKeyguardGoingAwayAnimation) + val values by collectValues(underTest.value.usingKeyguardGoingAwayAnimation) // Start on LOCKSCREEN. transitionRepository.sendTransitionStep( @@ -319,9 +338,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { } @Test + @DisableSceneContainer fun lockscreenVisibility_visibleWhenGone() = testScope.runTest { - val values by collectValues(underTest.lockscreenVisibility) + val values by collectValues(underTest.value.lockscreenVisibility) // Start on LOCKSCREEN. transitionRepository.sendTransitionStep( @@ -385,9 +405,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { } @Test + @DisableSceneContainer fun testLockscreenVisibility_usesFromState_ifCanceled() = testScope.runTest { - val values by collectValues(underTest.lockscreenVisibility) + val values by collectValues(underTest.value.lockscreenVisibility) transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, @@ -486,9 +507,10 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { * state during the AOD/isAsleep -> GONE transition is AOD (where lockscreen visibility = true). */ @Test + @DisableSceneContainer fun testLockscreenVisibility_falseDuringTransitionToGone_fromCanceledGone() = testScope.runTest { - val values by collectValues(underTest.lockscreenVisibility) + val values by collectValues(underTest.value.lockscreenVisibility) transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, @@ -587,11 +609,11 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { ) } - /** */ @Test + @DisableSceneContainer fun testLockscreenVisibility_trueDuringTransitionToGone_fromNotCanceledGone() = testScope.runTest { - val values by collectValues(underTest.lockscreenVisibility) + val values by collectValues(underTest.value.lockscreenVisibility) transitionRepository.sendTransitionSteps( from = KeyguardState.LOCKSCREEN, @@ -702,4 +724,109 @@ class WindowManagerLockscreenVisibilityInteractorTest : SysuiTestCase() { values ) } + + @Test + @EnableSceneContainer + fun sceneContainer_lockscreenVisibility_visibleWhenNotGone() = + testScope.runTest { + val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility) + + sceneTransitions.value = lsToGone + assertThat(lockscreenVisibility).isTrue() + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone) + assertThat(lockscreenVisibility).isFalse() + + sceneTransitions.value = goneToLs + assertThat(lockscreenVisibility).isFalse() + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen) + assertThat(lockscreenVisibility).isTrue() + } + + @Test + @EnableSceneContainer + fun sceneContainer_lockscreenVisibility_notVisibleWhenReturningToGone() = + testScope.runTest { + val lockscreenVisibility by collectLastValue(underTest.value.lockscreenVisibility) + + sceneTransitions.value = goneToLs + assertThat(lockscreenVisibility).isFalse() + + sceneTransitions.value = lsToGone + assertThat(lockscreenVisibility).isFalse() + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone) + assertThat(lockscreenVisibility).isFalse() + + sceneTransitions.value = goneToLs + assertThat(lockscreenVisibility).isFalse() + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen) + assertThat(lockscreenVisibility).isTrue() + } + + @Test + @EnableSceneContainer + fun sceneContainer_usingGoingAwayAnimation_duringTransitionToGone() = + testScope.runTest { + val usingKeyguardGoingAwayAnimation by + collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation) + + sceneTransitions.value = lsToGone + assertThat(usingKeyguardGoingAwayAnimation).isTrue() + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone) + assertThat(usingKeyguardGoingAwayAnimation).isFalse() + } + + @Test + @EnableSceneContainer + fun sceneContainer_usingGoingAwayAnimation_surfaceBehindIsAnimating() = + testScope.runTest { + val usingKeyguardGoingAwayAnimation by + collectLastValue(underTest.value.usingKeyguardGoingAwayAnimation) + + sceneTransitions.value = lsToGone + surfaceBehindIsAnimatingFlow.emit(true) + assertThat(usingKeyguardGoingAwayAnimation).isTrue() + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone) + assertThat(usingKeyguardGoingAwayAnimation).isTrue() + + sceneTransitions.value = goneToLs + assertThat(usingKeyguardGoingAwayAnimation).isTrue() + + surfaceBehindIsAnimatingFlow.emit(false) + assertThat(usingKeyguardGoingAwayAnimation).isFalse() + } + + companion object { + private val progress = MutableStateFlow(0f) + + private val sceneTransitions = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Idle(Scenes.Lockscreen) + ) + + private val lsToGone = + ObservableTransitionState.Transition( + Scenes.Lockscreen, + Scenes.Gone, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + private val goneToLs = + ObservableTransitionState.Transition( + Scenes.Gone, + Scenes.Lockscreen, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt new file mode 100644 index 000000000000..8a5af09f52ed --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractorTest.kt @@ -0,0 +1,1318 @@ +/* + * 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.domain.interactor.scenetransition + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.coroutines.collectValues +import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository +import com.android.systemui.keyguard.data.repository.realKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.keyguard.shared.model.TransitionInfo +import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled +import com.android.systemui.keyguard.shared.model.TransitionState +import com.android.systemui.keyguard.shared.model.TransitionStep +import com.android.systemui.kosmos.testScope +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 kotlin.test.Test +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidJUnit4::class) +class LockscreenSceneTransitionInteractorTest : SysuiTestCase() { + private val kosmos = + testKosmos().apply { keyguardTransitionRepository = realKeyguardTransitionRepository } + + private val testScope = kosmos.testScope + private val underTest = kosmos.lockscreenSceneTransitionInteractor + + private val progress = MutableStateFlow(0f) + + private val sceneTransitions = + MutableStateFlow<ObservableTransitionState>( + ObservableTransitionState.Idle(Scenes.Lockscreen) + ) + + private val lsToGone = + ObservableTransitionState.Transition( + Scenes.Lockscreen, + Scenes.Gone, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + private val goneToLs = + ObservableTransitionState.Transition( + Scenes.Gone, + Scenes.Lockscreen, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + @Before + fun setUp() { + underTest.start() + kosmos.sceneContainerRepository.setTransitionState(sceneTransitions) + testScope.launch { + kosmos.realKeyguardTransitionRepository.emitInitialStepsFromOff( + KeyguardState.LOCKSCREEN + ) + } + } + + /** STL: Ls -> Gone, then settle with Idle(Gone). This is the default case. */ + @Test + fun transition_from_ls_scene_end_in_gone() = + testScope.runTest { + sceneTransitions.value = lsToGone + + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + assertTransition( + step = currentStep!!, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone) + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + + /** + * STL: Ls -> Gone, then settle with Idle(Ls). KTF in this scenario needs to invert the + * transition LS -> UNDEFINED to UNDEFINED -> LS as there is no mechanism in KTF to + * finish/settle to progress 0.0f. + */ + @Test + fun transition_from_ls_scene_end_in_ls() = + testScope.runTest { + sceneTransitions.value = lsToGone + + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + assertTransition( + step = currentStep!!, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen) + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.CANCELED, + progress = 0.4f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.STARTED, + progress = 0.6f, + ) + + assertTransition( + step = allSteps[allSteps.size - 1], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + + /** + * STL: Ls -> Gone, then settle with Idle(Ls). KTF starts in AOD and needs to inverse correctly + * back to AOD. + */ + @Test + fun transition_from_ls_scene_on_aod_end_in_ls() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + + kosmos.realKeyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = this.javaClass.simpleName, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + ) + sceneTransitions.value = lsToGone + + assertTransition( + step = currentStep!!, + from = KeyguardState.AOD, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + assertTransition( + step = currentStep!!, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen) + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.AOD, + to = KeyguardState.UNDEFINED, + state = TransitionState.CANCELED, + progress = 0.4f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.UNDEFINED, + to = KeyguardState.AOD, + state = TransitionState.STARTED, + progress = 0.6f, + ) + + assertTransition( + step = allSteps[allSteps.size - 1], + from = KeyguardState.UNDEFINED, + to = KeyguardState.AOD, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + + /** + * STL: Gone -> Ls, then settle with Idle(Ls). This is the default case in the reverse + * direction. + */ + @Test + fun transition_to_ls_scene_end_in_ls() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = goneToLs + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + assertTransition( + step = currentStep!!, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen) + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + + /** STL: Gone -> Ls (AOD), will transition to AOD once */ + @Test + fun transition_to_ls_scene_with_changed_next_scene_is_respected_just_once() = + testScope.runTest { + underTest.onSceneAboutToChange(Scenes.Lockscreen, KeyguardState.AOD) + sceneTransitions.value = goneToLs + + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.AOD, + state = TransitionState.RUNNING, + progress = 0f, + ) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Shade, + Scenes.Lockscreen, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0f, + ) + } + + /** + * STL: Gone -> Ls, then settle with Idle(Gone). KTF in this scenario needs to invert the + * transition UNDEFINED -> LS to LS -> UNDEFINED as there is no mechanism in KTF to + * finish/settle to progress 0.0f. + */ + @Test + fun transition_to_ls_scene_end_in_from_scene() = + testScope.runTest { + sceneTransitions.value = goneToLs + + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + assertTransition( + step = currentStep!!, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone) + val stepM3 = allSteps[allSteps.size - 3] + val stepM2 = allSteps[allSteps.size - 2] + + assertTransition( + step = stepM3, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.CANCELED, + progress = 0.4f, + ) + + assertTransition( + step = stepM2, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.STARTED, + progress = 0.6f, + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + + /** + * STL: Gone -> Ls, then interrupted by Shade -> Ls. KTF in this scenario needs to invert the + * transition UNDEFINED -> LS to LS -> UNDEFINED as there is no mechanism in KTF to + * finish/settle to progress 0.0f. Then restart a different transition UNDEFINED -> Ls. + */ + @Test + fun transition_to_ls_scene_end_in_to_ls_transition() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = goneToLs + progress.value = 0.4f + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Shade, + Scenes.Lockscreen, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = allSteps[allSteps.size - 5], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.CANCELED, + progress = 0.4f, + ) + + assertTransition( + step = allSteps[allSteps.size - 4], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.STARTED, + progress = 0.6f, + ) + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.FINISHED, + progress = 1f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.STARTED, + progress = 0f, + ) + + progress.value = 0.2f + assertTransition( + step = allSteps[allSteps.size - 1], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0.2f, + ) + } + + /** + * STL: Gone -> Ls, then interrupted by Ls -> Shade. This is like continuing the transition from + * Ls before the transition before has properly settled. This can happen in STL e.g. with an + * accelerated swipe (quick successive fling gestures). + */ + @Test + fun transition_to_ls_scene_end_in_from_ls_transition() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = goneToLs + progress.value = 0.4f + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Lockscreen, + Scenes.Shade, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.CANCELED, + progress = 0.4f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.STARTED, + progress = 0.0f, + ) + + progress.value = 0.2f + assertTransition( + step = allSteps[allSteps.size - 1], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0.2f, + ) + } + + /** + * STL: Gone -> Ls, then interrupted by Gone -> Shade. This is going back to Gone but starting a + * transition from Gone before settling in Gone. KTF needs to make sure the transition is + * properly inversed and settled in UNDEFINED. + */ + @Test + fun transition_to_ls_scene_end_in_other_transition() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = goneToLs + progress.value = 0.4f + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Gone, + Scenes.Shade, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.CANCELED, + progress = 0.4f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.STARTED, + progress = 0.6f, + ) + + assertTransition( + step = allSteps[allSteps.size - 1], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + + /** + * STL: Gone -> Ls, then interrupt in KTF LS -> AOD, then stl still finishes in Ls. After a KTF + * transition is started (UNDEFINED -> LOCKSCREEN) KTF immediately considers the active scene to + * be LOCKSCREEN. This means that all listeners for LOCKSCREEN are active and may start a new + * transition LOCKSCREEN -> *. Here we test LS -> AOD. + * + * KTF is allowed to already start and play the other transition, while the STL transition may + * finish later (gesture completes much later). When we eventually settle the STL transition in + * Ls we do not want to force KTF back to its original destination (LOCKSCREEN). Instead, for + * this scenario the settle can be ignored. + */ + @Test + fun transition_to_ls_scene_interrupted_by_ktf_transition_then_finish_in_lockscreen() = + testScope.runTest { + sceneTransitions.value = goneToLs + + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + assertTransition( + step = currentStep!!, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + kosmos.realKeyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = this.javaClass.simpleName, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.STARTED, + progress = 0f, + ) + + // Scene progress should not affect KTF transition anymore + progress.value = 0.7f + assertTransition(currentStep!!, progress = 0f) + + // Scene transition still finishes but should not impact KTF transition + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Lockscreen) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.STARTED, + progress = 0f, + ) + } + + /** + * STL: Gone -> Ls, then interrupt in KTF LS -> AOD, then stl finishes in Gone. + * + * Refers to: `transition_to_ls_scene_interrupted_by_ktf_transition_then_finish_in_lockscreen` + * + * This is similar to the previous scenario but the gesture may have gone back to its origin. In + * this case we can not ignore the settlement, because whatever KTF has done in the meantime it + * needs to immediately finish in UNDEFINED (there is a jump cut). + */ + @Test + fun transition_to_ls_scene_interrupted_by_ktf_transition_then_finish_in_gone() = + testScope.runTest { + sceneTransitions.value = goneToLs + + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + assertTransition( + step = currentStep!!, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + kosmos.realKeyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = this.javaClass.simpleName, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.STARTED, + progress = 0f, + ) + + progress.value = 0.7f + assertThat(currentStep?.value).isEqualTo(0f) + + sceneTransitions.value = ObservableTransitionState.Idle(Scenes.Gone) + + assertTransition( + step = currentStep!!, + from = KeyguardState.AOD, + to = KeyguardState.UNDEFINED, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + + /** + * STL: Gone -> Ls, then interrupt in KTF LS -> AOD, then STL Gone -> Shade + * + * Refers to: `transition_to_ls_scene_interrupted_by_ktf_transition_then_finish_in_lockscreen` + * + * This is similar to the previous scenario but the gesture may have been interrupted by any + * other transition. KTF needs to immediately finish in UNDEFINED (there is a jump cut). + */ + @Test + fun transition_to_ls_interrupted_by_ktf_transition_then_interrupted_by_other_transition() = + testScope.runTest { + sceneTransitions.value = goneToLs + + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + assertTransition( + step = currentStep!!, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + kosmos.realKeyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = this.javaClass.simpleName, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.STARTED, + progress = 0f, + ) + + progress.value = 0.7f + assertTransition(currentStep!!, progress = 0f) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Gone, + Scenes.Shade, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.AOD, + to = KeyguardState.UNDEFINED, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + + /** + * STL: Gone -> Ls, then interrupt in KTF LS -> AOD, then STL Ls -> Shade + * + * In this scenario it is important that the last STL transition Ls -> Shade triggers a cancel + * of the * -> AOD transition but then also properly starts a transition AOD (not LOCKSCREEN) -> + * UNDEFINED transition. + */ + @Test + fun transition_to_ls_interrupted_by_ktf_transition_then_interrupted_by_from_ls_transition() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = goneToLs + progress.value = 0.4f + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + kosmos.realKeyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = this.javaClass.simpleName, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.STARTED, + progress = 0f, + ) + + progress.value = 0.7f + assertTransition(currentStep!!, progress = 0f) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Lockscreen, + Scenes.Shade, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + allSteps[allSteps.size - 3] + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.CANCELED, + progress = 0f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.AOD, + to = KeyguardState.UNDEFINED, + state = TransitionState.STARTED, + progress = 0f, + ) + + progress.value = 0.2f + assertTransition( + step = allSteps[allSteps.size - 1], + from = KeyguardState.AOD, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0.2f, + ) + } + + /** + * STL: Gone -> Ls, then interrupt in KTF LS -> AOD, then STL Shade -> Ls + * + * In this scenario it is important KTF is brought back into a FINISHED UNDEFINED state + * considering the state is already on AOD from where a new UNDEFINED -> LOCKSCREEN transition + * can be started. + */ + @Test + fun transition_to_ls_interrupted_by_ktf_transition_then_interrupted_by_to_ls_transition() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = goneToLs + progress.value = 0.4f + + assertTransition( + step = currentStep!!, + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + kosmos.realKeyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = this.javaClass.simpleName, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.STARTED, + progress = 0f, + ) + + progress.value = 0.7f + assertTransition(currentStep!!, progress = 0f) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Shade, + Scenes.Lockscreen, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = allSteps[allSteps.size - 5], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.CANCELED, + progress = 0f, + ) + + assertTransition( + step = allSteps[allSteps.size - 4], + from = KeyguardState.AOD, + to = KeyguardState.UNDEFINED, + state = TransitionState.STARTED, + progress = 1f, + ) + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.AOD, + to = KeyguardState.UNDEFINED, + state = TransitionState.FINISHED, + progress = 1f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.STARTED, + progress = 0f, + ) + + assertTransition( + step = allSteps[allSteps.size - 1], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0.7f, + ) + } + + /** + * STL: Gone -> Ls, then interrupt multiple canceled KTF transitions, then STL Ls -> Shade + * + * Similar to + * `transition_to_ls_scene_interrupted_by_ktf_transition_then_interrupted_by_from_ls_transition` + * but here KTF is canceled multiple times such that in the end OCCLUDED -> UNDEFINED is + * properly started. (not from AOD or LOCKSCREEN) + * + * Note: there is no test which tests multiple cancels from the STL side, this is because all + * STL transitions trigger a response from LockscreenSceneTransitionInteractor which forces KTF + * into a specific state, so testing each pair is enough. Meanwhile KTF can move around without + * any reaction from LockscreenSceneTransitionInteractor. + */ + @Test + fun transition_to_ls_interrupted_by_ktf_cancel_sequence_interrupted_by_from_ls_transition() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = lsToGone + progress.value = 0.4f + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + kosmos.realKeyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = this.javaClass.simpleName, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.STARTED, + progress = 0f, + ) + + kosmos.realKeyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = this.javaClass.simpleName, + from = KeyguardState.AOD, + to = KeyguardState.DOZING, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.AOD, + to = KeyguardState.DOZING, + state = TransitionState.STARTED, + progress = 0f, + ) + + kosmos.realKeyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = this.javaClass.simpleName, + from = KeyguardState.DOZING, + to = KeyguardState.OCCLUDED, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.DOZING, + to = KeyguardState.OCCLUDED, + state = TransitionState.STARTED, + progress = 0f, + ) + + progress.value = 0.7f + assertTransition(currentStep!!, progress = 0f) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Lockscreen, + Scenes.Shade, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.DOZING, + to = KeyguardState.OCCLUDED, + state = TransitionState.CANCELED, + progress = 0f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.OCCLUDED, + to = KeyguardState.UNDEFINED, + state = TransitionState.STARTED, + progress = 0f, + ) + + progress.value = 0.2f + assertTransition( + step = allSteps[allSteps.size - 1], + from = KeyguardState.OCCLUDED, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0.2f, + ) + } + + /** + * STL: Gone -> Ls, then interrupted by KTF LS -> AOD which is FINISHED before STL Ls -> Shade + * + * Similar to + * `transition_to_ls_scene_interrupted_by_ktf_transition_then_interrupted_by_from_ls_transition` + * but here KTF is finishing the transition and only then gets interrupted. Should correctly + * start AOD -> UNDEFINED. + */ + @Test + fun transition_to_ls_scene_interrupted_and_finished_by_ktf_interrupted_by_from_ls_transition() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = lsToGone + progress.value = 0.4f + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + val ktfUuid = + kosmos.realKeyguardTransitionRepository.startTransition( + TransitionInfo( + ownerName = this.javaClass.simpleName, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + animator = null, + modeOnCanceled = TransitionModeOnCanceled.RESET + ) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.STARTED, + progress = 0f, + ) + + kosmos.realKeyguardTransitionRepository.updateTransition( + ktfUuid!!, + 1f, + TransitionState.FINISHED + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.FINISHED, + progress = 1f, + ) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Lockscreen, + Scenes.Shade, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.AOD, + state = TransitionState.FINISHED, + progress = 1f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.AOD, + to = KeyguardState.UNDEFINED, + state = TransitionState.STARTED, + progress = 0f, + ) + + progress.value = 0.2f + assertTransition( + step = allSteps[allSteps.size - 1], + from = KeyguardState.AOD, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0.2f, + ) + } + + /** + * STL: Ls -> Gone, then interrupted by Ls -> Bouncer. This happens when the next transition is + * immediately started from Gone without settling in Idle. This specifically happens when + * dragging down on Ls and then changing direction. The transition will switch from -> Shade to + * -> Bouncer without settling or signaling any cancellation as STL considers this to be the + * same gesture. + * + * In STL there is no guarantee that transitions settle in Idle before continuing. + */ + @Test + fun transition_from_ls_scene_interrupted_by_other_from_ls_transition() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = lsToGone + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0f, + ) + + progress.value = 0.4f + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Lockscreen, + Scenes.Bouncer, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = allSteps[allSteps.size - 5], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.CANCELED, + progress = 0.4f, + ) + + assertTransition( + step = allSteps[allSteps.size - 4], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.STARTED, + progress = 0.6f, + ) + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.FINISHED, + progress = 1f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.STARTED, + progress = 0f, + ) + } + + /** + * STL: Ls -> Gone, then interrupted by Gone -> Ls. This happens when the next transition is + * immediately started from Gone without settling in Idle. In STL there is no guarantee that + * transitions settle in Idle before continuing. + */ + @Test + fun transition_from_ls_scene_interrupted_by_to_ls_transition() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + val allSteps by collectValues(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = lsToGone + progress.value = 0.4f + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Gone, + Scenes.Lockscreen, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = allSteps[allSteps.size - 3], + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.FINISHED, + progress = 1f, + ) + + assertTransition( + step = allSteps[allSteps.size - 2], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.STARTED, + progress = 0f, + ) + + progress.value = 0.2f + assertTransition( + step = allSteps[allSteps.size - 1], + from = KeyguardState.UNDEFINED, + to = KeyguardState.LOCKSCREEN, + state = TransitionState.RUNNING, + progress = 0.2f, + ) + } + + /** + * STL: Ls -> Gone, then interrupted by Gone -> Bouncer. This happens when the next transition + * is immediately started from Gone without settling in Idle. In STL there is no guarantee that + * transitions settle in Idle before continuing. + */ + @Test + fun transition_from_ls_scene_interrupted_by_other_stl_transition() = + testScope.runTest { + val currentStep by collectLastValue(kosmos.realKeyguardTransitionRepository.transitions) + sceneTransitions.value = lsToGone + progress.value = 0.4f + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.RUNNING, + progress = 0.4f, + ) + + sceneTransitions.value = + ObservableTransitionState.Transition( + Scenes.Gone, + Scenes.Bouncer, + flowOf(Scenes.Lockscreen), + progress, + false, + flowOf(false) + ) + + assertTransition( + step = currentStep!!, + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.UNDEFINED, + state = TransitionState.FINISHED, + progress = 1f, + ) + } + + private fun assertTransition( + step: TransitionStep, + from: KeyguardState? = null, + to: KeyguardState? = null, + state: TransitionState? = null, + progress: Float? = null + ) { + if (from != null) assertThat(step.from).isEqualTo(from) + if (to != null) assertThat(step.to).isEqualTo(to) + if (state != null) assertThat(step.transitionState).isEqualTo(state) + if (progress != null) assertThat(step.value).isEqualTo(progress) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt index 2f650c4420a0..040d3b8f09cb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/KeyguardClockViewBinderTest.kt @@ -85,7 +85,6 @@ class KeyguardClockViewBinderTest : SysuiTestCase() { setupWeatherClock() KeyguardClockViewBinder.updateBurnInLayer(rootView, clockViewModel, ClockSize.LARGE) verify(burnInLayer).removeView(smallClockView) - verify(burnInLayer).addView(largeClockView) } @Test @@ -101,7 +100,6 @@ class KeyguardClockViewBinderTest : SysuiTestCase() { setupNonWeatherClock() KeyguardClockViewBinder.updateBurnInLayer(rootView, clockViewModel, ClockSize.SMALL) verify(burnInLayer).addView(smallClockView) - verify(burnInLayer).removeView(largeClockView) } private fun setupWeatherClock() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt index ba2efe6d7443..b3cc5c949cb8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/ClockSectionTest.kt @@ -32,6 +32,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardClockInteractor import com.android.systemui.keyguard.domain.interactor.keyguardSmartspaceInteractor import com.android.systemui.keyguard.shared.model.ClockSize import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel +import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope @@ -117,6 +118,7 @@ class ClockSectionTest : SysuiTestCase() { context, keyguardSmartspaceViewModel, { keyguardBlueprintInteractor }, + keyguardRootViewModel, ) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt index e56a25345436..265ade3fac0f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataFilterImplTest.kt @@ -172,20 +172,20 @@ class LegacyMediaDataFilterImplTest : SysuiTestCase() { fun testOnRemovedForCurrent_callsListener() { // GIVEN a media was removed for main user mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) - mediaDataFilter.onMediaDataRemoved(KEY) + mediaDataFilter.onMediaDataRemoved(KEY, false) // THEN we should tell the listener - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) } @Test fun testOnRemovedForGuest_doesNotCallListener() { // GIVEN a media was removed for guest user mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) - mediaDataFilter.onMediaDataRemoved(KEY) + mediaDataFilter.onMediaDataRemoved(KEY, false) // THEN we should NOT tell the listener - verify(listener, never()).onMediaDataRemoved(eq(KEY)) + verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean()) } @Test @@ -197,7 +197,7 @@ class LegacyMediaDataFilterImplTest : SysuiTestCase() { setUser(USER_GUEST) // THEN we should remove the main user's media - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) } @Test @@ -230,7 +230,7 @@ class LegacyMediaDataFilterImplTest : SysuiTestCase() { setPrivateProfileUnavailable() // THEN we should add the private profile media - verify(listener).onMediaDataRemoved(eq(KEY_ALT)) + verify(listener).onMediaDataRemoved(eq(KEY_ALT), eq(false)) } @Test @@ -360,7 +360,7 @@ class LegacyMediaDataFilterImplTest : SysuiTestCase() { @Test fun testOnNotificationRemoved_doesntHaveMedia() { mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain) - mediaDataFilter.onMediaDataRemoved(KEY) + mediaDataFilter.onMediaDataRemoved(KEY, false) assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isFalse() assertThat(mediaDataFilter.hasAnyMedia()).isFalse() } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt index 5a2d22d0d503..99bf2db2ff98 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/LegacyMediaDataManagerImplTest.kt @@ -346,7 +346,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { // THEN it is removed and listeners are informed foregroundExecutor.advanceClockToLast() foregroundExecutor.runAllReady() - verify(listener).onMediaDataRemoved(PACKAGE_NAME) + verify(listener).onMediaDataRemoved(PACKAGE_NAME, false) } @Test @@ -532,7 +532,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { addNotificationAndLoad() val data = mediaDataCaptor.value mediaDataManager.onNotificationRemoved(KEY) - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) } @@ -777,7 +777,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { eq(false) ) assertThat(mediaDataCaptor.value.resumption).isTrue() - verify(listener, never()).onMediaDataRemoved(eq(KEY)) + verify(listener, never()).onMediaDataRemoved(eq(KEY), eq(false)) // WHEN the second is removed mediaDataManager.onNotificationRemoved(KEY_2) // THEN the data is for resumption and the second key is removed @@ -791,7 +791,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { eq(false) ) assertThat(mediaDataCaptor.value.resumption).isTrue() - verify(listener).onMediaDataRemoved(eq(KEY_2)) + verify(listener).onMediaDataRemoved(eq(KEY_2), eq(false)) } @Test @@ -816,7 +816,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { mediaDataManager.onNotificationRemoved(KEY) // THEN the media data is removed - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) } @Test @@ -866,7 +866,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { mediaDataManager.onNotificationRemoved(KEY) // THEN the media data is removed - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) } @Test @@ -905,7 +905,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { assertThat(mediaDataCaptor.value.isPlaying).isFalse() // And the oldest resume control was removed - verify(listener).onMediaDataRemoved(eq("0:$PACKAGE_NAME")) + verify(listener).onMediaDataRemoved(eq("0:$PACKAGE_NAME"), eq(false)) } fun testOnNotificationRemoved_lockDownMode() { @@ -915,7 +915,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { val data = mediaDataCaptor.value mediaDataManager.onNotificationRemoved(KEY) - verify(listener, never()).onMediaDataRemoved(eq(KEY)) + verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean()) verify(logger, never()) .logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) @@ -1148,7 +1148,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { mediaDataManager.setMediaResumptionEnabled(false) // THEN the resume controls are dismissed - verify(listener).onMediaDataRemoved(eq(PACKAGE_NAME)) + verify(listener).onMediaDataRemoved(eq(PACKAGE_NAME), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) } @@ -1156,19 +1156,19 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { fun testDismissMedia_listenerCalled() { addNotificationAndLoad() val data = mediaDataCaptor.value - val removed = mediaDataManager.dismissMediaData(KEY, 0L) + val removed = mediaDataManager.dismissMediaData(KEY, 0L, true) assertThat(removed).isTrue() foregroundExecutor.advanceClockToLast() foregroundExecutor.runAllReady() - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(true)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) } @Test fun testDismissMedia_keyDoesNotExist_returnsFalse() { - val removed = mediaDataManager.dismissMediaData(KEY, 0L) + val removed = mediaDataManager.dismissMediaData(KEY, 0L, true) assertThat(removed).isFalse() } @@ -2077,7 +2077,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { sessionCallbackCaptor.value.invoke(KEY) // It remains as a regular player - verify(listener, never()).onMediaDataRemoved(eq(KEY)) + verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean()) verify(listener, never()) .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) } @@ -2093,7 +2093,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { mediaDataManager.onNotificationRemoved(KEY) // It is fully removed - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(listener, never()) .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) @@ -2146,7 +2146,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { mediaDataManager.onNotificationRemoved(KEY) // It remains as a regular player - verify(listener, never()).onMediaDataRemoved(eq(KEY)) + verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean()) verify(listener, never()) .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) } @@ -2199,7 +2199,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { sessionCallbackCaptor.value.invoke(KEY) // It is fully removed - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(listener, never()) .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) @@ -2253,7 +2253,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { sessionCallbackCaptor.value.invoke(KEY) // It is fully removed. - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(listener, never()) .onMediaDataLoaded( @@ -2279,7 +2279,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { sessionCallbackCaptor.value.invoke(KEY) // It is fully removed - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(listener, never()) .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) @@ -2329,7 +2329,7 @@ class LegacyMediaDataManagerImplTest : SysuiTestCase() { mediaDataManager.onNotificationRemoved(KEY) // We still make sure to remove it - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java index bb5b57287a9a..dd05a0d12429 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataCombineLatestTest.java @@ -202,24 +202,24 @@ public class MediaDataCombineLatestTest extends SysuiTestCase { @Test public void mediaDataRemoved() { // WHEN media data is removed without first receiving device or data - mManager.onMediaDataRemoved(KEY); + mManager.onMediaDataRemoved(KEY, false); // THEN a removed event isn't emitted - verify(mListener, never()).onMediaDataRemoved(eq(KEY)); + verify(mListener, never()).onMediaDataRemoved(eq(KEY), anyBoolean()); } @Test public void mediaDataRemovedAfterMediaEvent() { mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */, 0 /* receivedSmartspaceCardLatency */, false /* isSsReactivated */); - mManager.onMediaDataRemoved(KEY); - verify(mListener).onMediaDataRemoved(eq(KEY)); + mManager.onMediaDataRemoved(KEY, false); + verify(mListener).onMediaDataRemoved(eq(KEY), eq(false)); } @Test public void mediaDataRemovedAfterDeviceEvent() { mManager.onMediaDeviceChanged(KEY, null, mDeviceData); - mManager.onMediaDataRemoved(KEY); - verify(mListener).onMediaDataRemoved(eq(KEY)); + mManager.onMediaDataRemoved(KEY, false); + verify(mListener).onMediaDataRemoved(eq(KEY), eq(false)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt index 857af66cab16..35eefd91bc8e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataFilterImplTest.kt @@ -168,7 +168,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { @Test fun onDataLoadedForCurrentUser_updatesLoadedStates() = testScope.runTest { - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val mediaCommonModel = MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(dataMain.instanceId)) @@ -176,13 +176,13 @@ class MediaDataFilterImplTest : SysuiTestCase() { verify(listener) .onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true), eq(0), eq(false)) - assertThat(sortedMedia?.values).containsExactly(mediaCommonModel) + assertThat(currentMedia).containsExactly(mediaCommonModel) } @Test fun onDataLoadedForGuest_doesNotUpdateLoadedStates() = testScope.runTest { - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val mediaCommonModel = MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(dataMain.instanceId)) @@ -190,64 +190,63 @@ class MediaDataFilterImplTest : SysuiTestCase() { verify(listener, never()) .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean()) - assertThat(sortedMedia?.values).doesNotContain(mediaCommonModel) + assertThat(currentMedia).doesNotContain(mediaCommonModel) } @Test fun onRemovedForCurrent_updatesLoadedStates() = testScope.runTest { - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val mediaCommonModel = MediaCommonModel.MediaControl(MediaDataLoadingModel.Loaded(dataMain.instanceId)) // GIVEN a media was removed for main user mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) - assertThat(sortedMedia?.values).containsExactly(mediaCommonModel) + assertThat(currentMedia).containsExactly(mediaCommonModel) - mediaDataFilter.onMediaDataRemoved(KEY) + mediaDataFilter.onMediaDataRemoved(KEY, false) - verify(listener).onMediaDataRemoved(eq(KEY)) - assertThat(sortedMedia?.values).doesNotContain(mediaCommonModel) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) + assertThat(currentMedia).doesNotContain(mediaCommonModel) } @Test fun onRemovedForGuest_doesNotUpdateLoadedStates() = testScope.runTest { - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) // GIVEN a media was removed for guest user mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) - mediaDataFilter.onMediaDataRemoved(KEY) + mediaDataFilter.onMediaDataRemoved(KEY, false) - verify(listener, never()).onMediaDataRemoved(eq(KEY)) - assertThat(sortedMedia).isEmpty() + verify(listener, never()).onMediaDataRemoved(eq(KEY), eq(false)) + assertThat(currentMedia).isEmpty() } @Test fun onUserSwitched_removesOldUserControls() = testScope.runTest { - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val mediaLoaded = MediaDataLoadingModel.Loaded(dataMain.instanceId) // GIVEN that we have a media loaded for main user mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) - assertThat(sortedMedia?.values) - .containsExactly(MediaCommonModel.MediaControl(mediaLoaded)) + assertThat(currentMedia).containsExactly(MediaCommonModel.MediaControl(mediaLoaded)) // and we switch to guest user setUser(USER_GUEST) // THEN we should remove the main user's media - verify(listener).onMediaDataRemoved(eq(KEY)) - assertThat(sortedMedia).isEmpty() + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) + assertThat(currentMedia).isEmpty() } @Test fun onUserSwitched_addsNewUserControls() = testScope.runTest { - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val guestLoadedStatesModel = MediaDataLoadingModel.Loaded(dataGuest.instanceId) val mainLoadedStatesModel = MediaDataLoadingModel.Loaded(dataMain.instanceId) @@ -272,16 +271,16 @@ class MediaDataFilterImplTest : SysuiTestCase() { anyInt(), anyBoolean() ) - assertThat(sortedMedia?.values) + assertThat(currentMedia) .containsExactly(MediaCommonModel.MediaControl(guestLoadedStatesModel)) - assertThat(sortedMedia?.values) + assertThat(currentMedia) .doesNotContain(MediaCommonModel.MediaControl(mainLoadedStatesModel)) } @Test fun onProfileChanged_profileUnavailable_updateStates() = testScope.runTest { - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) // GIVEN that we had some media for both profiles mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) @@ -292,8 +291,8 @@ class MediaDataFilterImplTest : SysuiTestCase() { val mediaLoadedStatesModel = MediaDataLoadingModel.Loaded(dataMain.instanceId) // THEN we should remove the private profile media - verify(listener).onMediaDataRemoved(eq(KEY_ALT)) - assertThat(sortedMedia?.values) + verify(listener).onMediaDataRemoved(eq(KEY_ALT), eq(false)) + assertThat(currentMedia) .containsExactly(MediaCommonModel.MediaControl(mediaLoadedStatesModel)) } @@ -503,7 +502,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain) - mediaDataFilter.onMediaDataRemoved(KEY) + mediaDataFilter.onMediaDataRemoved(KEY, false) assertThat(hasAnyMediaOrRecommendation(selectedUserEntries, smartspaceMediaData)) .isFalse() assertThat(hasAnyMedia(selectedUserEntries)).isFalse() @@ -523,13 +522,13 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val recommendationsLoadingModel = SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY, isPrioritized = true) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) - assertThat(sortedMedia?.values) + assertThat(currentMedia) .containsExactly(MediaCommonModel.MediaRecommendations(recommendationsLoadingModel)) assertThat( hasActiveMediaOrRecommendation( @@ -552,13 +551,13 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) whenever(smartspaceData.isActive).thenReturn(false) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) - assertThat(sortedMedia).isEmpty() + assertThat(currentMedia).isEmpty() assertThat( hasActiveMediaOrRecommendation( selectedUserEntries, @@ -581,7 +580,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val recsCommonModel = MediaCommonModel.MediaRecommendations( SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY, isPrioritized = true) @@ -596,7 +595,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { clock.advanceTime(MediaDataFilterImpl.SMARTSPACE_MAX_AGE + 100) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) - assertThat(sortedMedia?.values).containsExactly(recsCommonModel, controlCommonModel) + assertThat(currentMedia).containsExactly(recsCommonModel, controlCommonModel) assertThat( hasActiveMediaOrRecommendation( selectedUserEntries, @@ -618,7 +617,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) whenever(smartspaceData.isActive).thenReturn(false) val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) @@ -626,7 +625,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { clock.advanceTime(MediaDataFilterImpl.SMARTSPACE_MAX_AGE + 100) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) - assertThat(sortedMedia?.values) + assertThat(currentMedia) .doesNotContain( MediaCommonModel.MediaRecommendations( SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) @@ -652,7 +651,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) whenever(smartspaceData.isActive).thenReturn(false) @@ -665,7 +664,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { ) mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel) verify(listener) .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) @@ -673,7 +672,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) // THEN we should treat the media as not active instead - assertThat(sortedMedia?.values).containsExactly(controlCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel) assertThat( hasActiveMediaOrRecommendation( selectedUserEntries, @@ -696,7 +695,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) whenever(smartspaceData.isValid()).thenReturn(false) // WHEN we have media that was recently played, but not currently active @@ -707,7 +706,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { true ) mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel) verify(listener) .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) @@ -717,7 +716,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { // THEN we should treat the media as active instead val dataCurrentAndActive = dataCurrent.copy(active = true) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel) assertThat( hasActiveMediaOrRecommendation( selectedUserEntries, @@ -747,7 +746,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) // WHEN we have media that was recently played, but not currently active val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) val controlCommonModel = @@ -762,7 +761,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel) verify(listener) .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) @@ -790,7 +789,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { ) .isTrue() // Smartspace update should also be propagated but not prioritized. - assertThat(sortedMedia?.values).containsExactly(controlCommonModel, recsCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel) verify(listener) .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID) @@ -803,13 +802,13 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) - assertThat(sortedMedia?.values).isEmpty() + assertThat(currentMedia).isEmpty() assertThat( hasActiveMediaOrRecommendation( selectedUserEntries, @@ -827,7 +826,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val controlCommonModel = MediaCommonModel.MediaControl( MediaDataLoadingModel.Loaded(dataMain.instanceId), @@ -836,7 +835,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel) verify(listener) .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) @@ -857,7 +856,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel) assertThat( hasActiveMediaOrRecommendation( selectedUserEntries, @@ -875,7 +874,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val recsCommonModel = MediaCommonModel.MediaRecommendations( SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) @@ -887,7 +886,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { verify(listener) .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) - assertThat(sortedMedia?.values).containsExactly(recsCommonModel) + assertThat(currentMedia).containsExactly(recsCommonModel) assertThat( hasActiveMediaOrRecommendation( selectedUserEntries, @@ -906,7 +905,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val recsCommonModel = MediaCommonModel.MediaRecommendations( SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) @@ -926,7 +925,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { verify(listener) .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel) // And an inactive recommendation is loaded mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) @@ -936,7 +935,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) verify(listener, never()) .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean()) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel, recsCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel) assertThat( hasActiveMediaOrRecommendation( selectedUserEntries, @@ -974,7 +973,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { val selectedUserEntries by collectLastValue(repository.selectedUserEntries) val smartspaceMediaData by collectLastValue(repository.smartspaceMediaData) val reactivatedKey by collectLastValue(repository.reactivatedId) - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val recsCommonModel = MediaCommonModel.MediaRecommendations( SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) @@ -990,7 +989,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { verify(listener) .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel) // AND we get a smartspace signal with extra to trigger resume runCurrent() @@ -1009,7 +1008,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { eq(100), eq(true) ) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel, recsCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel) assertThat( hasActiveMediaOrRecommendation( selectedUserEntries, @@ -1026,7 +1025,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { @Test fun smartspaceLoaded_notShouldTriggerResume_doesNotTrigger() = testScope.runTest { - val sortedMedia by collectLastValue(repository.sortedMedia) + val currentMedia by collectLastValue(repository.currentMedia) val recsCommonModel = MediaCommonModel.MediaRecommendations( SmartspaceMediaLoadingModel.Loaded(SMARTSPACE_KEY) @@ -1043,7 +1042,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { verify(listener) .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false)) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel) // AND we get a smartspace signal with extra to not trigger resume val extras = Bundle().apply { putBoolean(EXTRA_KEY_TRIGGER_RESUME, false) } @@ -1056,7 +1055,7 @@ class MediaDataFilterImplTest : SysuiTestCase() { // But the smartspace update is still propagated verify(listener) .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false)) - assertThat(sortedMedia?.values).containsExactly(controlCommonModel, recsCommonModel) + assertThat(currentMedia).containsExactly(controlCommonModel, recsCommonModel) } private fun hasActiveMediaOrRecommendation( diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt index 1de7ee339c3e..5791826ab1f9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDataProcessorTest.kt @@ -384,7 +384,7 @@ class MediaDataProcessorTest : SysuiTestCase() { // THEN it is removed and listeners are informed foregroundExecutor.advanceClockToLast() foregroundExecutor.runAllReady() - verify(listener).onMediaDataRemoved(PACKAGE_NAME) + verify(listener).onMediaDataRemoved(PACKAGE_NAME, false) } @Test @@ -567,7 +567,7 @@ class MediaDataProcessorTest : SysuiTestCase() { addNotificationAndLoad() val data = mediaDataCaptor.value mediaDataProcessor.onNotificationRemoved(KEY) - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) } @@ -812,7 +812,7 @@ class MediaDataProcessorTest : SysuiTestCase() { eq(false) ) assertThat(mediaDataCaptor.value.resumption).isTrue() - verify(listener, never()).onMediaDataRemoved(eq(KEY)) + verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean()) // WHEN the second is removed mediaDataProcessor.onNotificationRemoved(KEY_2) // THEN the data is for resumption and the second key is removed @@ -826,7 +826,7 @@ class MediaDataProcessorTest : SysuiTestCase() { eq(false) ) assertThat(mediaDataCaptor.value.resumption).isTrue() - verify(listener).onMediaDataRemoved(eq(KEY_2)) + verify(listener).onMediaDataRemoved(eq(KEY_2), eq(false)) } @Test @@ -851,7 +851,7 @@ class MediaDataProcessorTest : SysuiTestCase() { mediaDataProcessor.onNotificationRemoved(KEY) // THEN the media data is removed - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) } @Test @@ -901,7 +901,7 @@ class MediaDataProcessorTest : SysuiTestCase() { mediaDataProcessor.onNotificationRemoved(KEY) // THEN the media data is removed - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) } @Test @@ -940,7 +940,7 @@ class MediaDataProcessorTest : SysuiTestCase() { assertThat(mediaDataCaptor.value.isPlaying).isFalse() // And the oldest resume control was removed - verify(listener).onMediaDataRemoved(eq("0:$PACKAGE_NAME")) + verify(listener).onMediaDataRemoved(eq("0:$PACKAGE_NAME"), eq(false)) } fun testOnNotificationRemoved_lockDownMode() { @@ -950,7 +950,7 @@ class MediaDataProcessorTest : SysuiTestCase() { val data = mediaDataCaptor.value mediaDataProcessor.onNotificationRemoved(KEY) - verify(listener, never()).onMediaDataRemoved(eq(KEY)) + verify(listener, never()).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger, never()) .logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) @@ -1183,7 +1183,7 @@ class MediaDataProcessorTest : SysuiTestCase() { mediaDataProcessor.setMediaResumptionEnabled(false) // THEN the resume controls are dismissed - verify(listener).onMediaDataRemoved(eq(PACKAGE_NAME)) + verify(listener).onMediaDataRemoved(eq(PACKAGE_NAME), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) } @@ -1191,19 +1191,19 @@ class MediaDataProcessorTest : SysuiTestCase() { fun testDismissMedia_listenerCalled() { addNotificationAndLoad() val data = mediaDataCaptor.value - val removed = mediaDataProcessor.dismissMediaData(KEY, 0L) + val removed = mediaDataProcessor.dismissMediaData(KEY, 0L, true) assertThat(removed).isTrue() foregroundExecutor.advanceClockToLast() foregroundExecutor.runAllReady() - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(true)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) } @Test fun testDismissMedia_keyDoesNotExist_returnsFalse() { - val removed = mediaDataProcessor.dismissMediaData(KEY, 0L) + val removed = mediaDataProcessor.dismissMediaData(KEY, 0L, true) assertThat(removed).isFalse() } @@ -2102,7 +2102,7 @@ class MediaDataProcessorTest : SysuiTestCase() { sessionCallbackCaptor.value.invoke(KEY) // It remains as a regular player - verify(listener, never()).onMediaDataRemoved(eq(KEY)) + verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean()) verify(listener, never()) .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) } @@ -2118,7 +2118,7 @@ class MediaDataProcessorTest : SysuiTestCase() { mediaDataProcessor.onNotificationRemoved(KEY) // It is fully removed - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(listener, never()) .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) @@ -2171,7 +2171,7 @@ class MediaDataProcessorTest : SysuiTestCase() { mediaDataProcessor.onNotificationRemoved(KEY) // It remains as a regular player - verify(listener, never()).onMediaDataRemoved(eq(KEY)) + verify(listener, never()).onMediaDataRemoved(eq(KEY), anyBoolean()) verify(listener, never()) .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) } @@ -2224,7 +2224,7 @@ class MediaDataProcessorTest : SysuiTestCase() { sessionCallbackCaptor.value.invoke(KEY) // It is fully removed - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(listener, never()) .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) @@ -2278,7 +2278,7 @@ class MediaDataProcessorTest : SysuiTestCase() { sessionCallbackCaptor.value.invoke(KEY) // It is fully removed. - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(listener, never()) .onMediaDataLoaded( @@ -2304,7 +2304,7 @@ class MediaDataProcessorTest : SysuiTestCase() { sessionCallbackCaptor.value.invoke(KEY) // It is fully removed - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId)) verify(listener, never()) .onMediaDataLoaded(eq(PACKAGE_NAME), any(), any(), anyBoolean(), anyInt(), anyBoolean()) @@ -2354,7 +2354,7 @@ class MediaDataProcessorTest : SysuiTestCase() { mediaDataProcessor.onNotificationRemoved(KEY) // We still make sure to remove it - verify(listener).onMediaDataRemoved(eq(KEY)) + verify(listener).onMediaDataRemoved(eq(KEY), eq(false)) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt index a447e442a384..befe64c1f411 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaDeviceManagerTest.kt @@ -60,6 +60,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor +import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt import org.mockito.Mock import org.mockito.Mockito.any @@ -158,7 +159,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test fun removeUnknown() { - manager.onMediaDataRemoved("unknown") + manager.onMediaDataRemoved("unknown", false) + verify(listener, never()).onKeyRemoved(eq(KEY), anyBoolean()) } @Test @@ -170,7 +172,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { @Test fun loadAndRemoveMediaData() { manager.onMediaDataLoaded(KEY, null, mediaData) - manager.onMediaDataRemoved(KEY) + manager.onMediaDataRemoved(KEY, false) fakeBgExecutor.runAllReady() verify(lmm).unregisterCallback(any()) verify(muteAwaitManager).stopListening() @@ -386,9 +388,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() { fun listenerReceivesKeyRemoved() { manager.onMediaDataLoaded(KEY, null, mediaData) // WHEN the notification is removed - manager.onMediaDataRemoved(KEY) + manager.onMediaDataRemoved(KEY, true) // THEN the listener receives key removed event - verify(listener).onKeyRemoved(eq(KEY)) + verify(listener).onKeyRemoved(eq(KEY), eq(true)) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilterTest.kt index 5a3c220b3d23..030bca25c518 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilterTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaSessionBasedFilterTest.kt @@ -165,10 +165,10 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { @Test fun noMediaSession_removedEventNotFiltered() { - filter.onMediaDataRemoved(KEY) + filter.onMediaDataRemoved(KEY, false) bgExecutor.runAllReady() fgExecutor.runAllReady() - verify(mediaListener).onMediaDataRemoved(eq(KEY)) + verify(mediaListener).onMediaDataRemoved(eq(KEY), eq(false)) } @Test @@ -193,11 +193,11 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { whenever(mediaSessionManager.getActiveSessions(any())).thenReturn(controllers) sessionListener.onActiveSessionsChanged(controllers) // WHEN a removed event is received - filter.onMediaDataRemoved(KEY) + filter.onMediaDataRemoved(KEY, false) bgExecutor.runAllReady() fgExecutor.runAllReady() // THEN the event is not filtered - verify(mediaListener).onMediaDataRemoved(eq(KEY)) + verify(mediaListener).onMediaDataRemoved(eq(KEY), eq(false)) } @Test @@ -294,7 +294,7 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() { anyBoolean() ) // AND there should be a removed event for key2 - verify(mediaListener).onMediaDataRemoved(eq(key2)) + verify(mediaListener).onMediaDataRemoved(eq(key2), eq(false)) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt index 3cc65c9524a8..cdbf9d757ec1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/domain/pipeline/MediaTimeoutListenerTest.kt @@ -166,12 +166,12 @@ class MediaTimeoutListenerTest : SysuiTestCase() { @Test fun testOnMediaDataRemoved_unregistersPlaybackListener() { mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData) - mediaTimeoutListener.onMediaDataRemoved(KEY) + mediaTimeoutListener.onMediaDataRemoved(KEY, false) verify(mediaController).unregisterCallback(anyObject()) // Ignores duplicate requests clearInvocations(mediaController) - mediaTimeoutListener.onMediaDataRemoved(KEY) + mediaTimeoutListener.onMediaDataRemoved(KEY, false) verify(mediaController, never()).unregisterCallback(anyObject()) } @@ -181,7 +181,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() { mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData) assertThat(executor.numPending()).isEqualTo(1) // WHEN the media is removed - mediaTimeoutListener.onMediaDataRemoved(KEY) + mediaTimeoutListener.onMediaDataRemoved(KEY, false) // THEN the timeout runnable is cancelled assertThat(executor.numPending()).isEqualTo(0) } @@ -398,7 +398,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() { // WHEN we have a resume control testOnMediaDataLoaded_resumption_registersTimeout() // AND the media is removed - mediaTimeoutListener.onMediaDataRemoved(PACKAGE) + mediaTimeoutListener.onMediaDataRemoved(PACKAGE, false) // THEN the timeout runnable is cancelled assertThat(executor.numPending()).isEqualTo(0) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt index 0a5aace91481..3bb8b8fcd775 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt @@ -33,6 +33,8 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.SysuiTestCase import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager +import com.android.systemui.flags.Flags +import com.android.systemui.flags.fakeFeatureFlagsClassic import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState @@ -74,12 +76,14 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestDispatcher import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock +import org.mockito.Mockito.anyLong import org.mockito.Mockito.floatThat import org.mockito.Mockito.mock import org.mockito.Mockito.never @@ -136,6 +140,9 @@ class MediaCarouselControllerTest : SysuiTestCase() { private lateinit var testDispatcher: TestDispatcher private lateinit var mediaCarouselController: MediaCarouselController + private var originalResumeSetting = + Settings.Secure.getInt(context.contentResolver, Settings.Secure.MEDIA_CONTROLS_RESUME, 1) + @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -186,6 +193,15 @@ class MediaCarouselControllerTest : SysuiTestCase() { ) } + @After + fun tearDown() { + Settings.Secure.putInt( + context.contentResolver, + Settings.Secure.MEDIA_CONTROLS_RESUME, + originalResumeSetting + ) + } + @Test fun testPlayerOrdering() { // Test values: key, data, last active time @@ -822,6 +838,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Test fun testKeyguardGone_showMediaCarousel() = kosmos.testScope.runTest { + kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false) var updatedVisibility = false mediaCarouselController.updateHostVisibility = { updatedVisibility = true } mediaCarouselController.mediaCarousel = mediaCarousel @@ -844,6 +861,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Test fun keyguardShowing_notAllowedOnLockscreen_updateVisibility() { kosmos.testScope.runTest { + kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false) var updatedVisibility = false mediaCarouselController.updateHostVisibility = { updatedVisibility = true } mediaCarouselController.mediaCarousel = mediaCarousel @@ -870,6 +888,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Test fun keyguardShowing_allowedOnLockscreen_updateVisibility() { kosmos.testScope.runTest { + kosmos.fakeFeatureFlagsClassic.set(Flags.MEDIA_RETAIN_RECOMMENDATIONS, false) var updatedVisibility = false mediaCarouselController.updateHostVisibility = { updatedVisibility = true } mediaCarouselController.mediaCarousel = mediaCarousel @@ -968,6 +987,45 @@ class MediaCarouselControllerTest : SysuiTestCase() { verify(panel).updateAnimatorDurationScale() } + @Test + fun swipeToDismiss_pausedAndResumeOff_userInitiated() { + // When resumption is disabled, paused media should be dismissed after being swiped away + Settings.Secure.putInt(context.contentResolver, Settings.Secure.MEDIA_CONTROLS_RESUME, 0) + + val pausedMedia = DATA.copy(isPlaying = false) + listener.value.onMediaDataLoaded(PAUSED_LOCAL, PAUSED_LOCAL, pausedMedia) + mediaCarouselController.onSwipeToDismiss() + + // When it can be removed immediately on update + whenever(visualStabilityProvider.isReorderingAllowed).thenReturn(true) + val inactiveMedia = pausedMedia.copy(active = false) + listener.value.onMediaDataLoaded(PAUSED_LOCAL, PAUSED_LOCAL, inactiveMedia) + + // This is processed as a user-initiated dismissal + verify(debugLogger).logMediaRemoved(eq(PAUSED_LOCAL), eq(true)) + verify(mediaDataManager).dismissMediaData(eq(PAUSED_LOCAL), anyLong(), eq(true)) + } + + @Test + fun swipeToDismiss_pausedAndResumeOff_delayed_userInitiated() { + // When resumption is disabled, paused media should be dismissed after being swiped away + Settings.Secure.putInt(context.contentResolver, Settings.Secure.MEDIA_CONTROLS_RESUME, 0) + mediaCarouselController.updateHostVisibility = {} + + val pausedMedia = DATA.copy(isPlaying = false) + listener.value.onMediaDataLoaded(PAUSED_LOCAL, PAUSED_LOCAL, pausedMedia) + mediaCarouselController.onSwipeToDismiss() + + // When it can't be removed immediately on update + whenever(visualStabilityProvider.isReorderingAllowed).thenReturn(false) + val inactiveMedia = pausedMedia.copy(active = false) + listener.value.onMediaDataLoaded(PAUSED_LOCAL, PAUSED_LOCAL, inactiveMedia) + visualStabilityCallback.value.onReorderingAllowed() + + // This is processed as a user-initiated dismissal + verify(mediaDataManager).dismissMediaData(eq(PAUSED_LOCAL), anyLong(), eq(true)) + } + /** * Helper method when a configuration change occurs. * diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt index 83e4d3130b67..0c9fee9e2741 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt @@ -1344,7 +1344,7 @@ public class MediaControlPanelTest : SysuiTestCase() { assertThat(dismiss.isEnabled).isEqualTo(true) dismiss.callOnClick() verify(logger).logLongPressDismiss(anyInt(), eq(PACKAGE), eq(instanceId)) - verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong()) + verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong(), eq(true)) } @Test @@ -1360,7 +1360,8 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun player_dismissButtonClick_notInManager() { val mediaKey = "key for dismissal" - whenever(mediaDataManager.dismissMediaData(eq(mediaKey), anyLong())).thenReturn(false) + whenever(mediaDataManager.dismissMediaData(eq(mediaKey), anyLong(), eq(true))) + .thenReturn(false) player.attachPlayer(viewHolder) val state = mediaData.copy(notificationKey = KEY) @@ -1369,8 +1370,8 @@ public class MediaControlPanelTest : SysuiTestCase() { assertThat(dismiss.isEnabled).isEqualTo(true) dismiss.callOnClick() - verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong()) - verify(mediaCarouselController).removePlayer(eq(mediaKey), eq(false), eq(false)) + verify(mediaDataManager).dismissMediaData(eq(mediaKey), anyLong(), eq(true)) + verify(mediaCarouselController).removePlayer(eq(mediaKey), eq(false), eq(false), eq(true)) } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java index ff7c970960e9..8f8630e90694 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java @@ -104,11 +104,11 @@ public class MediaDreamSentinelTest extends SysuiTestCase { listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true, /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false); - listener.onMediaDataRemoved(mKey); + listener.onMediaDataRemoved(mKey, false); verify(mDreamOverlayStateController, never()).removeComplication(any()); when(mMediaDataManager.hasActiveMedia()).thenReturn(false); - listener.onMediaDataRemoved(mKey); + listener.onMediaDataRemoved(mKey, false); verify(mDreamOverlayStateController).removeComplication(eq(mMediaEntryComplication)); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt index 8e0541008f59..c06a28e3d840 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/model/SysUiStateExtTest.kt @@ -42,13 +42,13 @@ class SysUiStateExtTest : SysuiTestCase() { fun updateFlags() { underTest.updateFlags( Display.DEFAULT_DISPLAY, - 1 to true, - 2 to false, - 3 to true, + 1L to true, + 2L to false, + 3L to true, ) - assertThat(underTest.flags and 1).isNotEqualTo(0) - assertThat(underTest.flags and 2).isEqualTo(0) - assertThat(underTest.flags and 3).isNotEqualTo(0) + assertThat(underTest.flags and 1L).isNotEqualTo(0L) + assertThat(underTest.flags and 2L).isEqualTo(0L) + assertThat(underTest.flags and 3L).isNotEqualTo(0L) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt index 9f0e67b60c29..85cc88dd5283 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/monet/ColorSchemeTest.kt @@ -15,11 +15,13 @@ */ package com.android.systemui.monet -import androidx.test.filters.SmallTest import android.testing.AndroidTestingRunner import android.util.Log +import android.util.Pair +import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.theme.DynamicColors +import com.google.ux.material.libmonet.dynamiccolor.DynamicColor import com.google.ux.material.libmonet.hct.Hct import com.google.ux.material.libmonet.scheme.SchemeTonalSpot import java.io.File @@ -81,6 +83,10 @@ private fun commentShade(paletteName: String, tone: Int): String { @SmallTest @RunWith(AndroidTestingRunner::class) class ColorSchemeTest : SysuiTestCase() { + private val defaultContrast = 0.0 + private val defaultIsDark = false + private val defaultIsFidelity = false + @Test fun generateThemeStyles() { val document = buildDoc<Any>() @@ -107,7 +113,7 @@ class ColorSchemeTest : SysuiTestCase() { } val style = document.createElement(styleValue.name.lowercase()) - val colorScheme = ColorScheme(sourceColor.toInt(), false, styleValue) + val colorScheme = ColorScheme(sourceColor.toInt(), defaultIsDark, styleValue) style.appendChild( document.createTextNode( @@ -139,7 +145,7 @@ class ColorSchemeTest : SysuiTestCase() { document.appendWithBreak(resources) // shade colors - val colorScheme = ColorScheme(GOOGLE_BLUE, false) + val colorScheme = ColorScheme(GOOGLE_BLUE, defaultIsDark) arrayOf( Triple("accent1", "Primary", colorScheme.accent1), Triple("accent2", "Secondary", colorScheme.accent2), @@ -162,24 +168,35 @@ class ColorSchemeTest : SysuiTestCase() { resources.appendWithBreak(document.createComment(commentRoles), 2) - // dynamic colors - arrayOf(false, true).forEach { isDark -> - val suffix = if (isDark) "_dark" else "_light" - val dynamicScheme = SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), isDark, 0.5) - DynamicColors.allDynamicColorsMapped(false).forEach { - resources.createColorEntry( - "system_${it.first}$suffix", - it.second.getArgb(dynamicScheme) - ) + fun generateDynamic(pairs: List<Pair<String, DynamicColor>>) { + arrayOf(false, true).forEach { isDark -> + val suffix = if (isDark) "_dark" else "_light" + val dynamicScheme = + SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), isDark, defaultContrast) + pairs.forEach { + resources.createColorEntry( + "system_${it.first}$suffix", + it.second.getArgb(dynamicScheme) + ) + } } } + // dynamic colors + generateDynamic(DynamicColors.allDynamicColorsMapped(defaultIsFidelity)) + // fixed colors - val dynamicScheme = SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), false, 0.5) - DynamicColors.getFixedColorsMapped(false).forEach { + val dynamicScheme = + SchemeTonalSpot(Hct.fromInt(GOOGLE_BLUE), defaultIsDark, defaultContrast) + DynamicColors.getFixedColorsMapped(defaultIsFidelity).forEach { resources.createColorEntry("system_${it.first}", it.second.getArgb(dynamicScheme)) } + resources.appendWithBreak(document.createComment(commentRoles), 2) + + // custom colors + generateDynamic(DynamicColors.getCustomColorsMapped(defaultIsFidelity)) + saveFile(document, "role_values.xml") } diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java index 224e75514ef6..2ff660f793cb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java @@ -125,7 +125,7 @@ public class NavBarHelperTest extends SysuiTestCase { private AccessibilityManager.AccessibilityServicesStateChangeListener mAccessibilityServicesStateChangeListener; - private static final int ACCESSIBILITY_BUTTON_CLICKABLE_STATE = + private static final long ACCESSIBILITY_BUTTON_CLICKABLE_STATE = SYSUI_STATE_A11Y_BUTTON_CLICKABLE | SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; private NavBarHelper mNavBarHelper; diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java index 0e7a21517913..6cea1e895e74 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java @@ -38,7 +38,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -300,7 +300,7 @@ public class NavigationBarTest extends SysuiTestCase { doNothing().when(mWindowManager).addView(any(), any()); doNothing().when(mWindowManager).removeViewImmediate(any()); mMockSysUiState = mock(SysUiState.class); - when(mMockSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mMockSysUiState); + when(mMockSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mMockSysUiState); mContext.addMockSystemService(WindowManager.class, mWindowManager); mSysuiTestableContextExternal.addMockSystemService(WindowManager.class, mWindowManager); diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt index 8d01e80d37d4..bba275e993fd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/TaskbarDelegateTest.kt @@ -16,18 +16,18 @@ import com.android.systemui.statusbar.phone.LightBarTransitionsController import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager import com.android.wm.shell.back.BackAnimation import com.android.wm.shell.pip.Pip +import java.util.Optional import org.junit.Before import org.junit.Test import org.mockito.ArgumentMatchers import org.mockito.Mock -import org.mockito.Mockito.`when` import org.mockito.Mockito.any import org.mockito.Mockito.anyBoolean -import org.mockito.Mockito.anyInt +import org.mockito.Mockito.anyLong import org.mockito.Mockito.times import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations -import java.util.Optional @SmallTest class TaskbarDelegateTest : SysuiTestCase() { @@ -74,7 +74,7 @@ class TaskbarDelegateTest : SysuiTestCase() { `when`(mNavBarHelper.edgeBackGestureHandler).thenReturn(mEdgeBackGestureHandler) `when`(mLightBarControllerFactory.create(any())).thenReturn(mLightBarTransitionController) `when`(mNavBarHelper.currentSysuiState).thenReturn(mCurrentSysUiState) - `when`(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState) + `when`(mSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mSysUiState) mTaskStackChangeListeners = TaskStackChangeListeners.getTestInstance() mTaskbarDelegate = TaskbarDelegate(context, mLightBarControllerFactory, mStatusBarKeyguardViewManager) diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java index f57f04000be9..68307b1b905e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java @@ -16,10 +16,12 @@ package com.android.systemui.qs.external; import static android.os.PowerExemptionManager.REASON_TILE_ONCLICK; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; import static android.service.quicksettings.TileService.START_ACTIVITY_NEEDS_PENDING_INTENT; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; @@ -55,13 +57,15 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.IDeviceIdleController; import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.FlagsParameterization; import android.service.quicksettings.IQSService; import android.service.quicksettings.IQSTileService; import android.service.quicksettings.TileService; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; -import androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -73,12 +77,24 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.InOrder; +import org.mockito.Mockito; import org.mockito.MockitoSession; +import java.util.List; + +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(ParameterizedAndroidJunit4.class) public class TileLifecycleManagerTest extends SysuiTestCase { + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX); + } + private final PackageManagerAdapter mMockPackageManagerAdapter = mock(PackageManagerAdapter.class); private final BroadcastDispatcher mMockBroadcastDispatcher = @@ -98,6 +114,11 @@ public class TileLifecycleManagerTest extends SysuiTestCase { private TestContextWrapper mWrappedContext; private MockitoSession mMockitoSession; + public TileLifecycleManagerTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setUp() throws Exception { setPackageEnabled(true); @@ -263,7 +284,8 @@ public class TileLifecycleManagerTest extends SysuiTestCase { } @Test - public void testNoClickOfNotListeningAnymore() throws Exception { + @DisableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) + public void testNoClickIfNotListeningAnymore() throws Exception { mStateManager.onTileAdded(); mStateManager.onStartListening(); mStateManager.onClick(null); @@ -279,6 +301,42 @@ public class TileLifecycleManagerTest extends SysuiTestCase { } @Test + @EnableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) + public void testNoClickIfNotListeningBeforeClick() throws Exception { + mStateManager.onTileAdded(); + mStateManager.onStartListening(); + mStateManager.onStopListening(); + mStateManager.onClick(null); + mStateManager.executeSetBindService(true); + mExecutor.runAllReady(); + + verifyBind(1); + mStateManager.executeSetBindService(false); + mExecutor.runAllReady(); + assertFalse(mContext.isBound(mTileServiceComponentName)); + verify(mMockTileService, never()).onClick(null); + } + + @Test + @EnableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) + public void testClickIfStopListeningBeforeProcessedClick() throws Exception { + mStateManager.onTileAdded(); + mStateManager.onStartListening(); + mStateManager.onClick(null); + mStateManager.onStopListening(); + mStateManager.executeSetBindService(true); + mExecutor.runAllReady(); + + verifyBind(1); + mStateManager.executeSetBindService(false); + mExecutor.runAllReady(); + assertFalse(mContext.isBound(mTileServiceComponentName)); + InOrder inOrder = Mockito.inOrder(mMockTileService); + inOrder.verify(mMockTileService).onClick(null); + inOrder.verify(mMockTileService).onStopListening(); + } + + @Test public void testComponentEnabling() throws Exception { mStateManager.onTileAdded(); mStateManager.onStartListening(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java index 0ff29dbbfde7..1c86638c9f27 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTest.java @@ -15,12 +15,18 @@ */ package com.android.systemui.qs.external; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; + +import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX; +import static com.android.systemui.util.concurrency.MockExecutorHandlerKt.mockExecutorHandler; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -32,16 +38,19 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; -import android.os.HandlerThread; import android.os.UserHandle; +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 androidx.test.runner.AndroidJUnit4; import com.android.systemui.SysuiTestCase; import com.android.systemui.qs.QSHost; import com.android.systemui.qs.pipeline.data.repository.CustomTileAddedRepository; import com.android.systemui.settings.UserTracker; +import com.android.systemui.util.concurrency.FakeExecutor; +import com.android.systemui.util.time.FakeSystemClock; import org.junit.After; import org.junit.Before; @@ -51,10 +60,20 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.List; + +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + @SmallTest -@RunWith(AndroidJUnit4.class) +@RunWith(ParameterizedAndroidJunit4.class) public class TileServiceManagerTest extends SysuiTestCase { + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX); + } + @Mock private TileServices mTileServices; @Mock @@ -68,17 +87,22 @@ public class TileServiceManagerTest extends SysuiTestCase { @Mock private CustomTileAddedRepository mCustomTileAddedRepository; - private HandlerThread mThread; - private Handler mHandler; + private FakeExecutor mFakeExecutor; + private TileServiceManager mTileServiceManager; private ComponentName mComponentName; + public TileServiceManagerTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - mThread = new HandlerThread("TestThread"); - mThread.start(); - mHandler = Handler.createAsync(mThread.getLooper()); + mFakeExecutor = new FakeExecutor(new FakeSystemClock()); + Handler handler = mockExecutorHandler(mFakeExecutor); + when(mUserTracker.getUserId()).thenReturn(UserHandle.USER_SYSTEM); when(mUserTracker.getUserHandle()).thenReturn(UserHandle.SYSTEM); @@ -90,13 +114,12 @@ public class TileServiceManagerTest extends SysuiTestCase { mComponentName = new ComponentName(mContext, TileServiceManagerTest.class); when(mTileLifecycle.getComponent()).thenReturn(mComponentName); - mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mUserTracker, + mTileServiceManager = new TileServiceManager(mTileServices, handler, mUserTracker, mCustomTileAddedRepository, mTileLifecycle); } @After public void tearDown() throws Exception { - mThread.quit(); mTileServiceManager.handleDestroy(); } @@ -201,4 +224,59 @@ public class TileServiceManagerTest extends SysuiTestCase { verify(mTileLifecycle, times(2)).executeSetBindService(captor.capture()); assertFalse((boolean) captor.getValue()); } + + @Test + @DisableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) + public void testStopListeningAndUnbindImmediatelyAfterUpdate() { + when(mTileLifecycle.isActiveTile()).thenReturn(true); + mTileServiceManager.startLifecycleManagerAndAddTile(); + mTileServiceManager.setBindAllowed(true); + clearInvocations(mTileLifecycle); + + mTileServiceManager.setBindRequested(true); + verify(mTileLifecycle).executeSetBindService(true); + + mTileServiceManager.setLastUpdate(0); + mFakeExecutor.advanceClockToLast(); + mFakeExecutor.runAllReady(); + verify(mTileLifecycle).onStopListening(); + verify(mTileLifecycle).executeSetBindService(false); + } + + @Test + @EnableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) + public void testStopListeningAndUnbindImmediatelyAfterUpdate_ifRequestedFromTileService() { + when(mTileLifecycle.isActiveTile()).thenReturn(true); + mTileServiceManager.startLifecycleManagerAndAddTile(); + mTileServiceManager.setBindAllowed(true); + clearInvocations(mTileLifecycle); + + mTileServiceManager.setBindRequested(true); + mTileServiceManager.onStartListeningFromRequest(); + verify(mTileLifecycle).onStartListening(); + + mTileServiceManager.setLastUpdate(0); + mFakeExecutor.advanceClockToLast(); + mFakeExecutor.runAllReady(); + verify(mTileLifecycle).onStopListening(); + verify(mTileLifecycle).executeSetBindService(false); + } + + @Test + @EnableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) + public void testNotUnbindImmediatelyAfterUpdate_ifRequestedFromSystemUI() { + when(mTileLifecycle.isActiveTile()).thenReturn(true); + mTileServiceManager.startLifecycleManagerAndAddTile(); + mTileServiceManager.setBindAllowed(true); + clearInvocations(mTileLifecycle); + + mTileServiceManager.setBindRequested(true); + // The tile requests startListening (because a click happened) + + mTileServiceManager.setLastUpdate(0); + mFakeExecutor.advanceClockToLast(); + mFakeExecutor.runAllReady(); + verify(mTileLifecycle, never()).onStopListening(); + verify(mTileLifecycle, never()).executeSetBindService(false); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java index b62d59d3a2f2..bcff88a49ad6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java @@ -15,6 +15,10 @@ */ package com.android.systemui.qs.external; +import static android.platform.test.flag.junit.FlagsParameterization.allCombinationsOf; + +import static com.android.systemui.Flags.FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; @@ -33,8 +37,10 @@ import android.os.Binder; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.FlagsParameterization; import android.service.quicksettings.IQSTileService; -import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; @@ -64,13 +70,23 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.List; import javax.inject.Provider; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + @SmallTest -@RunWith(AndroidTestingRunner.class) +@RunWith(ParameterizedAndroidJunit4.class) @RunWithLooper public class TileServicesTest extends SysuiTestCase { + + @Parameters(name = "{0}") + public static List<FlagsParameterization> getParams() { + return allCombinationsOf(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX); + } + private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2; private static final ComponentName TEST_COMPONENT = @@ -106,6 +122,11 @@ public class TileServicesTest extends SysuiTestCase { @Mock private CustomTileAddedRepository mCustomTileAddedRepository; + public TileServicesTest(FlagsParameterization flags) { + super(); + mSetFlagsRule.setFlagsParameterization(flags); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -194,6 +215,7 @@ public class TileServicesTest extends SysuiTestCase { } @Test + @DisableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) public void testRequestListeningStatusCommand() throws RemoteException { ArgumentCaptor<CommandQueue.Callbacks> captor = ArgumentCaptor.forClass(CommandQueue.Callbacks.class); @@ -213,6 +235,26 @@ public class TileServicesTest extends SysuiTestCase { } @Test + @EnableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) + public void testRequestListeningStatusCommand_onStartListeningFromRequest() { + ArgumentCaptor<CommandQueue.Callbacks> captor = + ArgumentCaptor.forClass(CommandQueue.Callbacks.class); + verify(mCommandQueue).addCallback(captor.capture()); + + CustomTile mockTile = mock(CustomTile.class); + when(mockTile.getComponent()).thenReturn(TEST_COMPONENT); + + TileServiceManager manager = mTileService.getTileWrapper(mockTile); + when(manager.isActiveTile()).thenReturn(true); + when(manager.getTileService()).thenReturn(mock(IQSTileService.class)); + + captor.getValue().requestTileServiceListeningState(TEST_COMPONENT); + mTestableLooper.processAllMessages(); + verify(manager).setBindRequested(true); + verify(manager).onStartListeningFromRequest(); + } + + @Test public void testValidCustomTileStartsActivity() { CustomTile tile = mock(CustomTile.class); PendingIntent pi = mock(PendingIntent.class); @@ -263,6 +305,7 @@ public class TileServicesTest extends SysuiTestCase { } @Test + @DisableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) public void tileFreedForCorrectUser() throws RemoteException { verify(mCommandQueue).addCallback(mCallbacksArgumentCaptor.capture()); @@ -297,6 +340,42 @@ public class TileServicesTest extends SysuiTestCase { verify(manager1.getTileService()).onStartListening(); } + @Test + @EnableFlags(FLAG_QS_CUSTOM_TILE_CLICK_GUARANTEED_BUG_FIX) + public void tileFreedForCorrectUser_onStartListeningFromRequest() throws RemoteException { + verify(mCommandQueue).addCallback(mCallbacksArgumentCaptor.capture()); + + ComponentName componentName = new ComponentName("pkg", "cls"); + CustomTile tileUser0 = mock(CustomTile.class); + CustomTile tileUser1 = mock(CustomTile.class); + + when(tileUser0.getComponent()).thenReturn(componentName); + when(tileUser1.getComponent()).thenReturn(componentName); + when(tileUser0.getUser()).thenReturn(0); + when(tileUser1.getUser()).thenReturn(1); + + // Create a tile for user 0 + TileServiceManager manager0 = mTileService.getTileWrapper(tileUser0); + when(manager0.isActiveTile()).thenReturn(true); + // Then create a tile for user 1 + TileServiceManager manager1 = mTileService.getTileWrapper(tileUser1); + when(manager1.isActiveTile()).thenReturn(true); + + // When the tile for user 0 gets freed + mTileService.freeService(tileUser0, manager0); + // and the user is 1 + when(mUserTracker.getUserId()).thenReturn(1); + + // a call to requestListeningState + mCallbacksArgumentCaptor.getValue().requestTileServiceListeningState(componentName); + mTestableLooper.processAllMessages(); + + // will call in the correct tile + verify(manager1).setBindRequested(true); + // and set it to listening + verify(manager1).onStartListeningFromRequest(); + } + private class TestTileServices extends TileServices { TestTileServices(QSHost host, Provider<Handler> handlerProvider, BroadcastDispatcher broadcastDispatcher, UserTracker userTracker, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt new file mode 100644 index 000000000000..db752dd64997 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorTest.kt @@ -0,0 +1,199 @@ +/* + * 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.qs.panels.domain.interactor + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.testScope +import com.android.systemui.qs.panels.data.repository.GridLayoutTypeRepository +import com.android.systemui.qs.panels.data.repository.IconTilesRepository +import com.android.systemui.qs.panels.data.repository.gridLayoutTypeRepository +import com.android.systemui.qs.panels.data.repository.iconTilesRepository +import com.android.systemui.qs.panels.shared.model.GridLayoutType +import com.android.systemui.qs.panels.shared.model.InfiniteGridLayoutType +import com.android.systemui.qs.pipeline.data.repository.tileSpecRepository +import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidTestingRunner::class) +class GridConsistencyInteractorTest : SysuiTestCase() { + + data object TestGridLayoutType : GridLayoutType + + private val gridLayout: MutableStateFlow<GridLayoutType> = + MutableStateFlow(InfiniteGridLayoutType) + + private val iconOnlyTiles = + MutableStateFlow( + setOf( + TileSpec.create("smallA"), + TileSpec.create("smallB"), + TileSpec.create("smallC"), + TileSpec.create("smallD"), + TileSpec.create("smallE"), + ) + ) + + private val kosmos = + testKosmos().apply { + iconTilesRepository = + object : IconTilesRepository { + override val iconTilesSpecs: StateFlow<Set<TileSpec>> + get() = iconOnlyTiles.asStateFlow() + } + gridConsistencyInteractorsMap = + mapOf( + Pair(InfiniteGridLayoutType, infiniteGridConsistencyInteractor), + Pair(TestGridLayoutType, noopGridConsistencyInteractor) + ) + gridLayoutTypeRepository = + object : GridLayoutTypeRepository { + override val layout: StateFlow<GridLayoutType> = gridLayout.asStateFlow() + } + } + + private val underTest = with(kosmos) { gridConsistencyInteractor } + + @Before + fun setUp() { + gridLayout.value = InfiniteGridLayoutType + underTest.start() + } + + @OptIn(ExperimentalCoroutinesApi::class) + @Test + fun changeLayoutType_usesCorrectGridConsistencyInteractor() = + with(kosmos) { + testScope.runTest { + // Using the no-op grid consistency interactor + gridLayout.value = TestGridLayoutType + + // Setting an invalid layout with holes + // [ Large A ] [ sa ] + // [ Large B ] [ Large C ] + // [ sb ] [ Large D ] + val newTiles = + listOf( + TileSpec.create("largeA"), + TileSpec.create("smallA"), + TileSpec.create("largeB"), + TileSpec.create("largeC"), + TileSpec.create("smallB"), + TileSpec.create("largeD"), + ) + tileSpecRepository.setTiles(0, newTiles) + + runCurrent() + + val tiles = currentTilesInteractor.currentTiles.value + val tileSpecs = tiles.map { it.spec } + + // Saved tiles should be unchanged + assertThat(tileSpecs).isEqualTo(newTiles) + } + } + + @Test + fun validTilesWithInfiniteGridConsistencyInteractor_unchangedList() = + with(kosmos) { + testScope.runTest { + // Setting a valid layout with holes + // [ Large A ] [ sa ][ sb ] + // [ Large B ] [ Large C ] + // [ Large D ] + val newTiles = + listOf( + TileSpec.create("largeA"), + TileSpec.create("smallA"), + TileSpec.create("smallB"), + TileSpec.create("largeB"), + TileSpec.create("largeC"), + TileSpec.create("largeD"), + ) + tileSpecRepository.setTiles(0, newTiles) + + runCurrent() + + val tiles = currentTilesInteractor.currentTiles.value + val tileSpecs = tiles.map { it.spec } + + // Saved tiles should be unchanged + assertThat(tileSpecs).isEqualTo(newTiles) + } + } + + @Test + fun invalidTilesWithInfiniteGridConsistencyInteractor_savesNewList() = + with(kosmos) { + testScope.runTest { + // Setting an invalid layout with holes + // [ sa ] [ Large A ] + // [ Large B ] [ sb ] [ sc ] + // [ sd ] [ se ] [ Large C ] + val newTiles = + listOf( + TileSpec.create("smallA"), + TileSpec.create("largeA"), + TileSpec.create("largeB"), + TileSpec.create("smallB"), + TileSpec.create("smallC"), + TileSpec.create("smallD"), + TileSpec.create("smallE"), + TileSpec.create("largeC"), + ) + tileSpecRepository.setTiles(0, newTiles) + + runCurrent() + + val tiles = currentTilesInteractor.currentTiles.value + val tileSpecs = tiles.map { it.spec } + + // Expected grid + // [ sa ] [ Large A ] [ sb ] + // [ Large B ] [ sc ] [ sd ] + // [ se ] [ Large C ] + val expectedTiles = + listOf( + TileSpec.create("smallA"), + TileSpec.create("largeA"), + TileSpec.create("smallB"), + TileSpec.create("largeB"), + TileSpec.create("smallC"), + TileSpec.create("smallD"), + TileSpec.create("smallE"), + TileSpec.create("largeC"), + ) + + // Saved tiles should be unchanged + assertThat(tileSpecs).isEqualTo(expectedTiles) + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt new file mode 100644 index 000000000000..bda48adbfcc3 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorTest.kt @@ -0,0 +1,195 @@ +/* + * 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.qs.panels.domain.interactor + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.testScope +import com.android.systemui.qs.panels.data.repository.IconTilesRepository +import com.android.systemui.qs.panels.data.repository.iconTilesRepository +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class InfiniteGridConsistencyInteractorTest : SysuiTestCase() { + + private val iconOnlyTiles = + MutableStateFlow( + setOf( + TileSpec.create("smallA"), + TileSpec.create("smallB"), + TileSpec.create("smallC"), + TileSpec.create("smallD"), + TileSpec.create("smallE"), + ) + ) + private val kosmos = + testKosmos().apply { + iconTilesRepository = + object : IconTilesRepository { + override val iconTilesSpecs: StateFlow<Set<TileSpec>> + get() = iconOnlyTiles.asStateFlow() + } + } + private val underTest = with(kosmos) { infiniteGridConsistencyInteractor } + + @Test + fun validTiles_returnsUnchangedList() = + with(kosmos) { + testScope.runTest { + // Original grid + // [ Large A ] [ sa ][ sb ] + // [ Large B ] [ Large C ] + // [ Large D ] + val tiles = + listOf( + TileSpec.create("largeA"), + TileSpec.create("smallA"), + TileSpec.create("smallB"), + TileSpec.create("largeB"), + TileSpec.create("largeC"), + TileSpec.create("largeD"), + ) + + val newTiles = underTest.reconcileTiles(tiles) + + assertThat(newTiles).isEqualTo(tiles) + } + } + + @Test + fun invalidTiles_moveIconTileForward() = + with(kosmos) { + testScope.runTest { + // Original grid + // [ Large A ] [ sa ] + // [ Large B ] [ Large C ] + // [ sb ] [ Large D ] + val tiles = + listOf( + TileSpec.create("largeA"), + TileSpec.create("smallA"), + TileSpec.create("largeB"), + TileSpec.create("largeC"), + TileSpec.create("smallB"), + TileSpec.create("largeD"), + ) + // Expected grid + // [ Large A ] [ sa ][ sb ] + // [ Large B ] [ Large C ] + // [ Large D ] + val expectedTiles = + listOf( + TileSpec.create("largeA"), + TileSpec.create("smallA"), + TileSpec.create("smallB"), + TileSpec.create("largeB"), + TileSpec.create("largeC"), + TileSpec.create("largeD"), + ) + + val newTiles = underTest.reconcileTiles(tiles) + + assertThat(newTiles).isEqualTo(expectedTiles) + } + } + + @Test + fun invalidTiles_moveIconTileBack() = + with(kosmos) { + testScope.runTest { + // Original grid + // [ sa ] [ Large A ] + // [ Large B ] [ Large C ] + // [ Large D ] + val tiles = + listOf( + TileSpec.create("smallA"), + TileSpec.create("largeA"), + TileSpec.create("largeB"), + TileSpec.create("largeC"), + TileSpec.create("largeD"), + ) + // Expected grid + // [ Large A ] [ Large B ] + // [ Large C ] [ Large D ] + // [ sa ] + val expectedTiles = + listOf( + TileSpec.create("largeA"), + TileSpec.create("largeB"), + TileSpec.create("largeC"), + TileSpec.create("largeD"), + TileSpec.create("smallA"), + ) + + val newTiles = underTest.reconcileTiles(tiles) + + assertThat(newTiles).isEqualTo(expectedTiles) + } + } + + @Test + fun invalidTiles_multipleCorrections() = + with(kosmos) { + testScope.runTest { + // Original grid + // [ sa ] [ Large A ] + // [ Large B ] [ sb ] [ sc ] + // [ sd ] [ se ] [ Large C ] + val tiles = + listOf( + TileSpec.create("smallA"), + TileSpec.create("largeA"), + TileSpec.create("largeB"), + TileSpec.create("smallB"), + TileSpec.create("smallC"), + TileSpec.create("smallD"), + TileSpec.create("smallE"), + TileSpec.create("largeC"), + ) + // Expected grid + // [ sa ] [ Large A ] [ sb ] + // [ Large B ] [ sc ] [ sd ] + // [ se ] [ Large C ] + val expectedTiles = + listOf( + TileSpec.create("smallA"), + TileSpec.create("largeA"), + TileSpec.create("smallB"), + TileSpec.create("largeB"), + TileSpec.create("smallC"), + TileSpec.create("smallD"), + TileSpec.create("smallE"), + TileSpec.create("largeC"), + ) + + val newTiles = underTest.reconcileTiles(tiles) + + assertThat(newTiles).isEqualTo(expectedTiles) + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java index f88a5a0d9f41..b75b3188ae64 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java @@ -20,7 +20,7 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotSame; import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -81,7 +81,7 @@ public class RearDisplayDialogControllerTest extends SysuiTestCase { public void setup() { MockitoAnnotations.initMocks(this); - when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState); + when(mSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mSysUiState); when(mSystemUIDialogFactory.create()).thenReturn(mSystemUIDialog); when(mSystemUIDialog.getContext()).thenReturn(mContext); } 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 effae5f67f02..74deae323b5c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/OverviewProxyServiceTest.kt @@ -72,7 +72,7 @@ import org.mockito.Mockito.any import org.mockito.Mockito.anyInt import org.mockito.Mockito.atLeast import org.mockito.Mockito.clearInvocations -import org.mockito.Mockito.intThat +import org.mockito.Mockito.longThat import org.mockito.Mockito.mock import org.mockito.Mockito.spy import org.mockito.Mockito.times @@ -162,7 +162,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { verify(overviewProxy) .onSystemUiStateChanged( - intThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_AWAKE } + longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_AWAKE } ) } @@ -172,7 +172,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { verify(overviewProxy) .onSystemUiStateChanged( - intThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_WAKING } + longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_WAKING } ) } @@ -182,7 +182,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { verify(overviewProxy) .onSystemUiStateChanged( - intThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_ASLEEP } + longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_ASLEEP } ) } @@ -194,7 +194,7 @@ class OverviewProxyServiceTest : SysuiTestCase() { verify(overviewProxy) .onSystemUiStateChanged( - intThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_GOING_TO_SLEEP } + longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_GOING_TO_SLEEP } ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt index 6846c7227d9c..fcc6b4f093ad 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/recordissue/RecordIssueDialogDelegateTest.kt @@ -55,6 +55,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyBoolean import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyLong import org.mockito.Mock import org.mockito.Mockito.never import org.mockito.Mockito.spy @@ -94,7 +95,7 @@ class RecordIssueDialogDelegateTest : SysuiTestCase() { fun setup() { MockitoAnnotations.initMocks(this) whenever(dprLazy.get()).thenReturn(devicePolicyResolver) - whenever(sysuiState.setFlag(anyInt(), anyBoolean())).thenReturn(sysuiState) + whenever(sysuiState.setFlag(anyLong(), anyBoolean())).thenReturn(sysuiState) whenever(screenCaptureDisabledDialogDelegate.createSysUIDialog()) .thenReturn(screenCaptureDisabledDialog) whenever( diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt index 5e53fe16534d..5cd3f66d2cbf 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentExecutorTest.kt @@ -23,17 +23,18 @@ import android.testing.AndroidTestingRunner import android.testing.TestableContext import com.android.systemui.Flags import com.android.systemui.SysuiTestCase +import com.android.systemui.screenshot.proxy.SystemUiProxy import com.android.systemui.settings.DisplayTracker import com.android.systemui.shared.system.ActivityManagerWrapper import com.android.systemui.statusbar.phone.CentralSurfaces -import com.android.systemui.util.mockito.mock import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestCoroutineScheduler import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mockito.verify +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify @RunWith(AndroidTestingRunner::class) class ActionIntentExecutorTest : SysuiTestCase() { @@ -44,8 +45,9 @@ class ActionIntentExecutorTest : SysuiTestCase() { private val testableContext = TestableContext(mContext) private val activityManagerWrapper = mock<ActivityManagerWrapper>() + private val systemUiProxy = mock<SystemUiProxy>() + private val displayTracker = mock<DisplayTracker>() - private val keyguardController = mock<ScreenshotKeyguardController>() private val actionIntentExecutor = ActionIntentExecutor( @@ -53,12 +55,12 @@ class ActionIntentExecutorTest : SysuiTestCase() { activityManagerWrapper, testScope, mainDispatcher, + systemUiProxy, displayTracker, - keyguardController, ) @Test - @EnableFlags(Flags.FLAG_SCREENSHOT_ACTION_DISMISS_SYSTEM_WINDOWS) + @EnableFlags(Flags.FLAG_FIX_SCREENSHOT_ACTION_DISMISS_SYSTEM_WINDOWS) fun launchIntent_callsCloseSystemWindows() = testScope.runTest { val intent = Intent(Intent.ACTION_EDIT).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK } diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt index 853e50a12ea5..896c3bf7547e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt @@ -37,6 +37,7 @@ import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.runner.RunWith import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.kotlin.never import org.mockito.kotlin.verify @RunWith(AndroidTestingRunner::class) @@ -111,6 +112,47 @@ class DefaultScreenshotActionsProviderTest : SysuiTestCase() { assertThat(intentCaptor.value.action).isEqualTo(Intent.ACTION_CHOOSER) } + @Test + fun scrollChipClicked_callsOnClick() = runTest { + actionsProvider = createActionsProvider() + + val onScrollClick = mock<Runnable>() + val numActions = viewModel.actions.value.size + actionsProvider.onScrollChipReady(onScrollClick) + viewModel.actions.value[numActions].onClicked!!.invoke() + + verify(onScrollClick).run() + } + + @Test + fun scrollChipClicked_afterInvalidate_doesNothing() = runTest { + actionsProvider = createActionsProvider() + + val onScrollClick = mock<Runnable>() + val numActions = viewModel.actions.value.size + actionsProvider.onScrollChipReady(onScrollClick) + actionsProvider.onScrollChipInvalidated() + viewModel.actions.value[numActions].onClicked!!.invoke() + + verify(onScrollClick, never()).run() + } + + @Test + fun scrollChipClicked_afterUpdate_runsNewAction() = runTest { + actionsProvider = createActionsProvider() + + val onScrollClick = mock<Runnable>() + val onScrollClick2 = mock<Runnable>() + val numActions = viewModel.actions.value.size + actionsProvider.onScrollChipReady(onScrollClick) + actionsProvider.onScrollChipInvalidated() + actionsProvider.onScrollChipReady(onScrollClick2) + viewModel.actions.value[numActions].onClicked!!.invoke() + + verify(onScrollClick2).run() + verify(onScrollClick, never()).run() + } + private fun createActionsProvider(): ScreenshotActionsProvider { return DefaultScreenshotActionsProvider( context, diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt index 537049c7b957..49a467e152ec 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt @@ -40,6 +40,7 @@ import com.android.systemui.communal.data.repository.fakeCommunalRepository import com.android.systemui.communal.domain.interactor.communalInteractor import com.android.systemui.communal.domain.interactor.setCommunalAvailable import com.android.systemui.communal.shared.model.CommunalScenes +import com.android.systemui.communal.ui.compose.CommunalContent import com.android.systemui.communal.ui.viewmodel.CommunalViewModel import com.android.systemui.communal.util.CommunalColors import com.android.systemui.coroutines.collectLastValue @@ -50,7 +51,6 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.res.R import com.android.systemui.scene.shared.model.sceneDataSourceDelegator import com.android.systemui.shade.domain.interactor.shadeInteractor -import com.android.systemui.statusbar.phone.SystemUIDialogFactory import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any import com.google.common.truth.Truth.assertThat @@ -83,9 +83,9 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { @Mock private lateinit var communalViewModel: CommunalViewModel @Mock private lateinit var powerManager: PowerManager - @Mock private lateinit var dialogFactory: SystemUIDialogFactory @Mock private lateinit var touchMonitor: TouchMonitor @Mock private lateinit var communalColors: CommunalColors + @Mock private lateinit var communalContent: CommunalContent private lateinit var ambientTouchComponentFactory: AmbientTouchComponent.Factory private lateinit var parentView: FrameLayout @@ -117,12 +117,12 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { GlanceableHubContainerController( communalInteractor, communalViewModel, - dialogFactory, keyguardInteractor, shadeInteractor, powerManager, communalColors, ambientTouchComponentFactory, + communalContent, kosmos.sceneDataSourceDelegator, ) } @@ -159,12 +159,12 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { GlanceableHubContainerController( communalInteractor, communalViewModel, - dialogFactory, keyguardInteractor, shadeInteractor, powerManager, communalColors, ambientTouchComponentFactory, + communalContent, kosmos.sceneDataSourceDelegator, ) @@ -303,12 +303,12 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { GlanceableHubContainerController( communalInteractor, communalViewModel, - dialogFactory, keyguardInteractor, shadeInteractor, powerManager, communalColors, ambientTouchComponentFactory, + communalContent, kosmos.sceneDataSourceDelegator, ) @@ -322,12 +322,12 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() { GlanceableHubContainerController( communalInteractor, communalViewModel, - dialogFactory, keyguardInteractor, shadeInteractor, powerManager, communalColors, ambientTouchComponentFactory, + communalContent, kosmos.sceneDataSourceDelegator, ) diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 5b47c94bcc90..766113f09308 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -655,7 +655,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { when(mView.getParent()).thenReturn(mViewParent); when(mQs.getHeader()).thenReturn(mQsHeader); when(mDownMotionEvent.getAction()).thenReturn(MotionEvent.ACTION_DOWN); - when(mSysUiState.setFlag(anyInt(), anyBoolean())).thenReturn(mSysUiState); + when(mSysUiState.setFlag(anyLong(), anyBoolean())).thenReturn(mSysUiState); mMainHandler = new Handler(Looper.getMainLooper()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java index 04fa5904d2e7..845744a54791 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java @@ -42,13 +42,10 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor; import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FakeFeatureFlagsClassic; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.keyguard.data.repository.FakeCommandQueue; import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository; -import com.android.systemui.keyguard.domain.interactor.FromLockscreenTransitionInteractor; -import com.android.systemui.keyguard.domain.interactor.FromPrimaryBouncerTransitionInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; import com.android.systemui.kosmos.KosmosJavaAdapter; @@ -59,9 +56,7 @@ import com.android.systemui.plugins.qs.QS; import com.android.systemui.power.domain.interactor.PowerInteractor; import com.android.systemui.qs.QSFragmentLegacy; import com.android.systemui.res.R; -import com.android.systemui.scene.data.repository.SceneContainerRepository; import com.android.systemui.scene.domain.interactor.SceneInteractor; -import com.android.systemui.scene.shared.logger.SceneLogger; import com.android.systemui.screenrecord.RecordingController; import com.android.systemui.shade.data.repository.FakeShadeRepository; import com.android.systemui.shade.domain.interactor.ShadeInteractor; @@ -176,12 +171,7 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase { protected Handler mMainHandler; protected LockscreenShadeTransitionController.Callback mLockscreenShadeTransitionCallback; - protected final ShadeExpansionStateManager mShadeExpansionStateManager = - new ShadeExpansionStateManager(); - protected FragmentHostManager.FragmentListener mFragmentListener; - private FromLockscreenTransitionInteractor mFromLockscreenTransitionInteractor; - private FromPrimaryBouncerTransitionInteractor mFromPrimaryBouncerTransitionInteractor; @Before public void setup() { @@ -190,19 +180,11 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase { mStatusBarStateController = mKosmos.getStatusBarStateController(); mKosmos.getFakeDeviceProvisioningRepository().setDeviceProvisioned(true); - FakeFeatureFlagsClassic featureFlags = new FakeFeatureFlagsClassic(); FakeConfigurationRepository configurationRepository = new FakeConfigurationRepository(); PowerInteractor powerInteractor = mKosmos.getPowerInteractor(); - SceneInteractor sceneInteractor = new SceneInteractor( - mTestScope.getBackgroundScope(), - new SceneContainerRepository( - mTestScope.getBackgroundScope(), - mKosmos.getFakeSceneContainerConfig(), - mKosmos.getSceneDataSource()), - mock(SceneLogger.class), - mKosmos.getDeviceUnlockedInteractor()); + SceneInteractor sceneInteractor = mKosmos.getSceneInteractor(); KeyguardTransitionInteractor keyguardTransitionInteractor = mKosmos.getKeyguardTransitionInteractor(); @@ -220,10 +202,6 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase { () -> mKosmos.getSharedNotificationContainerInteractor(), mTestScope); - mFromLockscreenTransitionInteractor = mKosmos.getFromLockscreenTransitionInteractor(); - mFromPrimaryBouncerTransitionInteractor = - mKosmos.getFromPrimaryBouncerTransitionInteractor(); - ResourcesSplitShadeStateController splitShadeStateController = new ResourcesSplitShadeStateController(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java index c08860906d0b..fe6a88d00374 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java @@ -51,6 +51,7 @@ import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeHeaderController; import com.android.systemui.shade.ShadeViewController; import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; +import com.android.systemui.shade.domain.interactor.ShadeInteractor; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; @@ -80,6 +81,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { @Mock private QuickSettingsController mQuickSettingsController; @Mock private ShadeViewController mShadeViewController; @Mock private PanelExpansionInteractor mPanelExpansionInteractor; + @Mock private Lazy<ShadeInteractor> mShadeInteractorLazy; @Mock private ShadeHeaderController mShadeHeaderController; @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; private final MetricsLogger mMetricsLogger = new FakeMetricsLogger(); @@ -115,6 +117,7 @@ public class CentralSurfacesCommandQueueCallbacksTest extends SysuiTestCase { mShadeController, mCommandQueue, mPanelExpansionInteractor, + mShadeInteractorLazy, mShadeHeaderController, mRemoteInputQuickSettingsDisabler, mMetricsLogger, diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java index ed7c9568a9db..a5e7a67b21a2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java @@ -995,9 +995,11 @@ public class ThemeOverlayControllerTest extends SysuiTestCase { .setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null)); // All dynamic colors were added twice: light and dark them // All fixed colors were added once + // All custom dynamic tokens added twice verify(dynamic, times( DynamicColors.allDynamicColorsMapped(false).size() * 2 - + DynamicColors.getFixedColorsMapped(false).size()) + + DynamicColors.getFixedColorsMapped(false).size() + + DynamicColors.getCustomColorsMapped(false).size() * 2) ).setResourceValue(any(String.class), eq(TYPE_INT_COLOR_ARGB8), anyInt(), eq(null)); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt index d1d259826ac2..15032dc182d6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/MockExecutorHandlerTest.kt @@ -141,6 +141,88 @@ class MockExecutorHandlerTest : SysuiTestCase() { assertEquals(3, runnable.mRunCount) } + @Test + fun testRemoveCallback_postDelayed() { + val clock = FakeSystemClock() + val fakeExecutor = FakeExecutor(clock) + val handler = mockExecutorHandler(fakeExecutor) + val runnable = RunnableImpl() + + handler.postDelayed(runnable, 50) + handler.postDelayed(runnable, 150) + fakeExecutor.advanceClockToNext() + fakeExecutor.runAllReady() + + assertEquals(1, runnable.mRunCount) + assertEquals(1, fakeExecutor.numPending()) + + handler.removeCallbacks(runnable) + assertEquals(0, fakeExecutor.numPending()) + + assertEquals(1, runnable.mRunCount) + } + + @Test + fun testRemoveCallback_postAtTime() { + val clock = FakeSystemClock() + val fakeExecutor = FakeExecutor(clock) + val handler = mockExecutorHandler(fakeExecutor) + val runnable = RunnableImpl() + assertEquals(10000, clock.uptimeMillis()) + + handler.postAtTime(runnable, 10050) + handler.postAtTime(runnable, 10150) + fakeExecutor.advanceClockToNext() + fakeExecutor.runAllReady() + + assertEquals(1, runnable.mRunCount) + assertEquals(1, fakeExecutor.numPending()) + + handler.removeCallbacks(runnable) + assertEquals(0, fakeExecutor.numPending()) + + assertEquals(1, runnable.mRunCount) + } + + @Test + fun testRemoveCallback_mixed_allRemoved() { + val clock = FakeSystemClock() + val fakeExecutor = FakeExecutor(clock) + val handler = mockExecutorHandler(fakeExecutor) + val runnable = RunnableImpl() + assertEquals(10000, clock.uptimeMillis()) + + handler.postAtTime(runnable, 10050) + handler.postDelayed(runnable, 150) + + handler.removeCallbacks(runnable) + assertEquals(0, fakeExecutor.numPending()) + + fakeExecutor.advanceClockToLast() + fakeExecutor.runAllReady() + assertEquals(0, runnable.mRunCount) + } + + @Test + fun testRemoveCallback_differentRunnables_onlyMatchingRemoved() { + val clock = FakeSystemClock() + val fakeExecutor = FakeExecutor(clock) + val handler = mockExecutorHandler(fakeExecutor) + val runnable1 = RunnableImpl() + val runnable2 = RunnableImpl() + + handler.postDelayed(runnable1, 50) + handler.postDelayed(runnable2, 150) + + handler.removeCallbacks(runnable1) + assertEquals(1, fakeExecutor.numPending()) + + fakeExecutor.advanceClockToLast() + fakeExecutor.runAllReady() + assertEquals(0, runnable1.mRunCount) + assertEquals(1, runnable2.mRunCount) + } + /** * Verifies that `Handler.removeMessages`, which doesn't make sense with executor backing, * causes an error in the test (rather than failing silently like most mocks). diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java index 3b468aa011ec..9864439266b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogImplTest.java @@ -65,7 +65,6 @@ import android.widget.ImageButton; import android.widget.SeekBar; import androidx.test.core.view.MotionEventBuilder; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import com.android.internal.jank.InteractionJankMonitor; @@ -273,54 +272,30 @@ public class VolumeDialogImplTest extends SysuiTestCase { @Test @DisableFlags(FLAG_HAPTIC_VOLUME_SLIDER) - public void testVolumeChange_noSliderHaptics_doesNotDeliverOnProgressChangedHaptics() { - final State shellState = createShellState(); - VolumeDialogController.StreamState musicStreamState = - shellState.states.get(AudioSystem.STREAM_MUSIC); - - mDialog.show(SHOW_REASON_UNKNOWN); - mTestableLooper.processMessages(1); //Only the SHOW message - mDialog.removeDismissMessages(); // Temporarily remove the rescheduled DISMISS - - // Change the volume two times - musicStreamState.level += 10; - mDialog.onStateChangedH(shellState); - musicStreamState.level += 10; - mDialog.onStateChangedH(shellState); + public void addSliderHaptics_withHapticsDisabled_doesNotDeliverOnProgressChangedHaptics() { + // GIVEN that the slider haptics flag is disabled and we try to add haptics to volume rows + mDialog.addSliderHapticsToRows(); - // expected: the type of the latest progress haptics for the stream should be DISABLED - int type = mDialog.progressHapticsForStream(AudioSystem.STREAM_MUSIC); - assertEquals(VolumeDialogImpl.PROGRESS_HAPTICS_DISABLED, type); + // WHEN haptics try to be delivered to a volume stream + boolean canDeliverHaptics = + mDialog.canDeliverProgressHapticsToStream(AudioSystem.STREAM_MUSIC, true, 50); - mDialog.dismiss(DISMISS_REASON_UNKNOWN); // Dismiss - mTestableLooper.processAllMessages(); + // THEN the result is that haptics are not successfully delivered + assertFalse(canDeliverHaptics); } - @Test @FlakyTest(bugId = 329099861) + @Test @EnableFlags(FLAG_HAPTIC_VOLUME_SLIDER) - public void testVolumeChange_withSliderHaptics_deliversOnProgressChangedHapticsEagerly() { - // create haptic plugins on the rows with the flag enabled + public void addSliderHaptics_withHapticsEnabled_canDeliverOnProgressChangedHaptics() { + // GIVEN that the slider haptics flag is enabled and we try to add haptics to volume rows mDialog.addSliderHapticsToRows(); - final State shellState = createShellState(); - VolumeDialogController.StreamState musicStreamState = - shellState.states.get(AudioSystem.STREAM_MUSIC); - - mDialog.show(SHOW_REASON_UNKNOWN); - mTestableLooper.processMessages(1); //Only the SHOW message - mDialog.removeDismissMessages(); // Temporarily remove the rescheduled DISMISS - // Change the volume two times - musicStreamState.level += 10; - mDialog.onStateChangedH(shellState); - musicStreamState.level += 10; - mDialog.onStateChangedH(shellState); + // WHEN haptics try to be delivered to a volume stream + boolean canDeliverHaptics = + mDialog.canDeliverProgressHapticsToStream(AudioSystem.STREAM_MUSIC, true, 50); - // expected: the type of the latest progress haptics for the stream should be EAGER - int type = mDialog.progressHapticsForStream(AudioSystem.STREAM_MUSIC); - assertEquals(VolumeDialogImpl.PROGRESS_HAPTICS_EAGER, type); - - mDialog.dismiss(DISMISS_REASON_UNKNOWN); // Dismiss - mTestableLooper.processAllMessages(); + // THEN the result is that haptics are successfully delivered + assertTrue(canDeliverHaptics); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index 56e5e293c799..aac36405e9b6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -138,7 +138,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.ScreenOffAnimationController; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt index 0975687b4744..e37bdc15c0ac 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/data/repository/FakePromptRepository.kt @@ -1,8 +1,6 @@ package com.android.systemui.biometrics.data.repository -import android.hardware.biometrics.Flags import android.hardware.biometrics.PromptInfo -import com.android.systemui.biometrics.Utils import com.android.systemui.biometrics.shared.model.PromptKind import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -22,15 +20,12 @@ class FakePromptRepository : PromptRepository { private var _challenge = MutableStateFlow<Long?>(null) override val challenge = _challenge.asStateFlow() - private val _kind = MutableStateFlow<PromptKind>(PromptKind.Biometric()) - override val kind = _kind.asStateFlow() + private val _promptKind = MutableStateFlow<PromptKind>(PromptKind.None) + override val promptKind = _promptKind.asStateFlow() private val _isConfirmationRequired = MutableStateFlow(false) override val isConfirmationRequired = _isConfirmationRequired.asStateFlow() - private val _showBpWithoutIconForCredential = MutableStateFlow(false) - override val showBpWithoutIconForCredential = _showBpWithoutIconForCredential.asStateFlow() - private val _opPackageName: MutableStateFlow<String?> = MutableStateFlow(null) override val opPackageName = _opPackageName.asStateFlow() @@ -61,7 +56,7 @@ class FakePromptRepository : PromptRepository { _promptInfo.value = promptInfo _userId.value = userId _challenge.value = gatekeeperChallenge - _kind.value = kind + _promptKind.value = kind _isConfirmationRequired.value = promptInfo.isConfirmationRequested || forceConfirmation _opPackageName.value = opPackageName } @@ -70,22 +65,11 @@ class FakePromptRepository : PromptRepository { _promptInfo.value = null _userId.value = null _challenge.value = null - _kind.value = PromptKind.Biometric() + _promptKind.value = PromptKind.None + _opPackageName.value = null _isConfirmationRequired.value = false } - override fun setShouldShowBpWithoutIconForCredential(promptInfo: PromptInfo) { - val hasCredentialViewShown = kind.value !is PromptKind.Biometric - val showBpForCredential = - Flags.customBiometricPrompt() && - com.android.systemui.Flags.constraintBp() && - !Utils.isBiometricAllowed(promptInfo) && - Utils.isDeviceCredentialAllowed(promptInfo) && - promptInfo.contentView != null && - !promptInfo.isContentViewMoreOptionsButtonUsed - _showBpWithoutIconForCredential.value = showBpForCredential && !hasCredentialViewShown - } - fun setIsShowing(showing: Boolean) { _isShowing.value = showing } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt index 2ae6f542ac3e..4999a5a29a7a 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelKosmos.kt @@ -17,6 +17,8 @@ package com.android.systemui.biometrics.ui.viewmodel import android.content.applicationContext +import com.android.app.activityTaskManager +import com.android.launcher3.icons.IconProvider import com.android.systemui.biometrics.domain.interactor.biometricStatusInteractor import com.android.systemui.biometrics.domain.interactor.displayStateInteractor import com.android.systemui.biometrics.domain.interactor.promptSelectorInteractor @@ -32,6 +34,8 @@ val Kosmos.promptViewModel by Fixture { context = applicationContext, udfpsOverlayInteractor = udfpsOverlayInteractor, biometricStatusInteractor = biometricStatusInteractor, - udfpsUtils = udfpsUtils + udfpsUtils = udfpsUtils, + iconProvider = IconProvider(applicationContext), + activityTaskManager = activityTaskManager, ) } 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 90a93f4e7544..a6b40df8e81b 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 @@ -24,6 +24,7 @@ import com.android.systemui.keyguard.ui.view.layout.blueprints.DefaultKeyguardBl import com.android.systemui.keyguard.ui.view.layout.blueprints.SplitShadeKeyguardBlueprint import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection import com.android.systemui.keyguard.ui.viewmodel.keyguardClockViewModel +import com.android.systemui.keyguard.ui.viewmodel.keyguardRootViewModel import com.android.systemui.keyguard.ui.viewmodel.keyguardSmartspaceViewModel import com.android.systemui.kosmos.Kosmos import com.android.systemui.util.mockito.mock @@ -37,6 +38,7 @@ val Kosmos.keyguardClockSection: ClockSection by context = applicationContext, smartspaceViewModel = keyguardSmartspaceViewModel, blueprintInteractor = { keyguardBlueprintInteractor }, + rootViewModel = keyguardRootViewModel, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.kt index 408157b7614f..3e69e875cd0d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryKosmos.kt @@ -17,7 +17,10 @@ package com.android.systemui.keyguard.data.repository import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testDispatcher var Kosmos.keyguardTransitionRepository: KeyguardTransitionRepository by Kosmos.Fixture { fakeKeyguardTransitionRepository } var Kosmos.fakeKeyguardTransitionRepository by Kosmos.Fixture { FakeKeyguardTransitionRepository() } +var Kosmos.realKeyguardTransitionRepository: KeyguardTransitionRepository by + Kosmos.Fixture { KeyguardTransitionRepositoryImpl(testDispatcher) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt new file mode 100644 index 000000000000..7d0e8b1b4b53 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/LockscreenSceneTransitionRepository.kt @@ -0,0 +1,22 @@ +/* + * 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.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.lockscreenSceneTransitionRepository by + Kosmos.Fixture { LockscreenSceneTransitionRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt index 29167d64d1f1..b38acc8a46dc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/WindowManagerLockscreenVisibilityInteractorKosmos.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.domain.interactor import com.android.systemui.kosmos.Kosmos +import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.statusbar.notification.domain.interactor.notificationLaunchAnimationInteractor val Kosmos.windowManagerLockscreenVisibilityInteractor by @@ -29,5 +30,6 @@ val Kosmos.windowManagerLockscreenVisibilityInteractor by fromBouncerInteractor = fromPrimaryBouncerTransitionInteractor, fromAlternateBouncerInteractor = fromAlternateBouncerTransitionInteractor, notificationLaunchAnimationInteractor = notificationLaunchAnimationInteractor, + sceneInteractor = sceneInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt new file mode 100644 index 000000000000..3c1f7b1b2394 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/scenetransition/LockscreenSceneTransitionInteractor.kt @@ -0,0 +1,33 @@ +/* + * 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.domain.interactor.scenetransition + +import com.android.systemui.keyguard.data.repository.lockscreenSceneTransitionRepository +import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.scene.domain.interactor.sceneInteractor + +var Kosmos.lockscreenSceneTransitionInteractor by + Kosmos.Fixture { + LockscreenSceneTransitionInteractor( + transitionInteractor = keyguardTransitionInteractor, + applicationScope = applicationCoroutineScope, + sceneInteractor = sceneInteractor, + repository = lockscreenSceneTransitionRepository, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt index 3f9112238822..d72630dc2f03 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/QuickSettingsKosmos.kt @@ -32,6 +32,7 @@ import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testDispatcher import com.android.systemui.plugins.activityStarter import com.android.systemui.plugins.qs.QSFactory +import com.android.systemui.plugins.qs.QSTile import com.android.systemui.qs.footer.domain.interactor.FooterActionsInteractorImpl import com.android.systemui.qs.footer.foregroundServicesRepository import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel @@ -48,7 +49,7 @@ val Kosmos.qsEventLogger: QsEventLoggerFake by Fixture { QsEventLoggerFake(uiEventLoggerFake, instanceIdSequenceFake) } -var Kosmos.qsTileFactory by Fixture<QSFactory>() +var Kosmos.qsTileFactory by Fixture<QSFactory> { FakeQSFactory(::tileCreator) } val Kosmos.fgsManagerController by Fixture { FakeFgsManagerController() } @@ -98,3 +99,7 @@ val Kosmos.footerActionsViewModelFactory by Fixture { showPowerButton = true, ) } + +private fun tileCreator(spec: String): QSTile { + return FakeQSTile(0).apply { tileSpec = spec } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/FakeIQSTileService.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/FakeIQSTileService.kt index cff59807e00f..744942c0053b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/FakeIQSTileService.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/FakeIQSTileService.kt @@ -16,11 +16,11 @@ package com.android.systemui.qs.external -import android.os.Binder import android.os.IBinder +import android.os.IInterface import android.service.quicksettings.IQSTileService -class FakeIQSTileService : IQSTileService { +class FakeIQSTileService : IQSTileService.Stub() { var isTileAdded: Boolean = false private set @@ -31,9 +31,11 @@ class FakeIQSTileService : IQSTileService { get() = mutableClicks private val mutableClicks: MutableList<IBinder?> = mutableListOf() - private val binder = Binder() + override fun queryLocalInterface(descriptor: String): IInterface { + return this + } - override fun asBinder(): IBinder = binder + override fun asBinder(): IBinder = this override fun onTileAdded() { isTileAdded = true diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerKosmos.kt new file mode 100644 index 000000000000..a0fc76b3d7de --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileLifecycleManagerKosmos.kt @@ -0,0 +1,44 @@ +/* + * 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.qs.external + +import android.app.activityManager +import android.content.applicationContext +import android.os.fakeExecutorHandler +import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.concurrency.fakeExecutor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.tiles.impl.custom.packageManagerAdapterFacade +import com.android.systemui.util.mockito.mock + +val Kosmos.tileLifecycleManagerFactory: TileLifecycleManager.Factory by + Kosmos.Fixture { + TileLifecycleManager.Factory { intent, userHandle -> + TileLifecycleManager( + fakeExecutorHandler, + applicationContext, + tileServices, + packageManagerAdapterFacade.packageManagerAdapter, + broadcastDispatcher, + intent, + userHandle, + activityManager, + mock(), + fakeExecutor, + ) + } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileServicesKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileServicesKosmos.kt new file mode 100644 index 000000000000..3f129dac2600 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TileServicesKosmos.kt @@ -0,0 +1,50 @@ +/* + * 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.qs.external + +import android.content.applicationContext +import android.os.fakeExecutorHandler +import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.concurrency.fakeExecutor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.QSHost +import com.android.systemui.qs.pipeline.data.repository.customTileAddedRepository +import com.android.systemui.qs.pipeline.domain.interactor.panelInteractor +import com.android.systemui.settings.userTracker +import com.android.systemui.statusbar.commandQueue +import com.android.systemui.statusbar.phone.ui.StatusBarIconController +import com.android.systemui.statusbar.policy.keyguardStateController +import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever + +val Kosmos.tileServices: TileServices by + Kosmos.Fixture { + val qsHost: QSHost = mock { whenever(context).thenReturn(applicationContext) } + TileServices( + qsHost, + { fakeExecutorHandler }, + broadcastDispatcher, + userTracker, + keyguardStateController, + commandQueue, + mock<StatusBarIconController>(), + panelInteractor, + tileLifecycleManagerFactory, + customTileAddedRepository, + fakeExecutor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TilesExternalKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TilesExternalKosmos.kt index 36c2c2b6eb23..9a6730e07666 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TilesExternalKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/external/TilesExternalKosmos.kt @@ -18,13 +18,9 @@ package com.android.systemui.qs.external import android.content.ComponentName import com.android.systemui.kosmos.Kosmos -import com.android.systemui.util.mockito.mock var Kosmos.componentName: ComponentName by Kosmos.Fixture() -/** Returns mocks */ -var Kosmos.tileLifecycleManagerFactory: TileLifecycleManager.Factory by Kosmos.Fixture { mock {} } - val Kosmos.iQSTileService: FakeIQSTileService by Kosmos.Fixture { FakeIQSTileService() } val Kosmos.tileServiceManagerFacade: FakeTileServiceManagerFacade by Kosmos.Fixture { FakeTileServiceManagerFacade(iQSTileService) } @@ -34,4 +30,3 @@ val Kosmos.tileServiceManager: TileServiceManager by val Kosmos.tileServicesFacade: FakeTileServicesFacade by Kosmos.Fixture { (FakeTileServicesFacade(tileServiceManager)) } -val Kosmos.tileServices: TileServices by Kosmos.Fixture { tileServicesFacade.tileServices } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryKosmos.kt index f846d5712497..4acedaa9044d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/GridLayoutTypeRepositoryKosmos.kt @@ -18,4 +18,5 @@ package com.android.systemui.qs.panels.data.repository import com.android.systemui.kosmos.Kosmos -val Kosmos.gridLayoutTypeRepository by Kosmos.Fixture { GridLayoutTypeRepository() } +var Kosmos.gridLayoutTypeRepository: GridLayoutTypeRepository by + Kosmos.Fixture { GridLayoutTypeRepositoryImpl() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconTilesRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconTilesRepositoryKosmos.kt index 685e77223fd5..e40152aa588f 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconTilesRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/IconTilesRepositoryKosmos.kt @@ -18,4 +18,4 @@ package com.android.systemui.qs.panels.data.repository import com.android.systemui.kosmos.Kosmos -val Kosmos.iconTilesRepository by Kosmos.Fixture { IconTilesRepositoryImpl() } +var Kosmos.iconTilesRepository: IconTilesRepository by Kosmos.Fixture { IconTilesRepositoryImpl() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/InfiniteGridSizeRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/InfiniteGridSizeRepositoryKosmos.kt new file mode 100644 index 000000000000..d8af3fa98d7b --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/data/repository/InfiniteGridSizeRepositoryKosmos.kt @@ -0,0 +1,21 @@ +/* + * 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.qs.panels.data.repository + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.infiniteGridSizeRepository by Kosmos.Fixture { InfiniteGridSizeRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorKosmos.kt new file mode 100644 index 000000000000..edbc4c1cd65e --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridConsistencyInteractorKosmos.kt @@ -0,0 +1,34 @@ +/* + * 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.qs.panels.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.log.core.FakeLogBuffer +import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor + +val Kosmos.gridConsistencyInteractor by + Kosmos.Fixture { + GridConsistencyInteractor( + gridLayoutTypeInteractor, + currentTilesInteractor, + gridConsistencyInteractorsMap, + noopGridConsistencyInteractor, + FakeLogBuffer.Factory.create(), + applicationCoroutineScope, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt index c9516429553b..34e99d3a9a3c 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/GridLayoutTypeInteractorKosmos.kt @@ -27,3 +27,6 @@ val Kosmos.gridLayoutTypeInteractor by val Kosmos.gridLayoutMap: Map<GridLayoutType, GridLayout> by Kosmos.Fixture { mapOf(Pair(InfiniteGridLayoutType, infiniteGridLayout)) } + +var Kosmos.gridConsistencyInteractorsMap: Map<GridLayoutType, GridTypeConsistencyInteractor> by + Kosmos.Fixture { mapOf(Pair(InfiniteGridLayoutType, infiniteGridConsistencyInteractor)) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorKosmos.kt new file mode 100644 index 000000000000..7f387d7c706d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridConsistencyInteractorKosmos.kt @@ -0,0 +1,24 @@ +/* + * 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.qs.panels.domain.interactor + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.infiniteGridConsistencyInteractor by + Kosmos.Fixture { + InfiniteGridConsistencyInteractor(iconTilesInteractor, infiniteGridSizeInteractor) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt index 1893c302c332..34b266a54f41 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridLayoutKosmos.kt @@ -19,4 +19,5 @@ package com.android.systemui.qs.panels.domain.interactor import com.android.systemui.kosmos.Kosmos import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout -val Kosmos.infiniteGridLayout by Kosmos.Fixture { InfiniteGridLayout(iconTilesInteractor) } +val Kosmos.infiniteGridLayout by + Kosmos.Fixture { InfiniteGridLayout(iconTilesInteractor, infiniteGridSizeInteractor) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridSizeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridSizeInteractorKosmos.kt new file mode 100644 index 000000000000..6e1197737630 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/InfiniteGridSizeInteractorKosmos.kt @@ -0,0 +1,23 @@ +/* + * 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.qs.panels.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.panels.data.repository.infiniteGridSizeRepository + +val Kosmos.infiniteGridSizeInteractor by + Kosmos.Fixture { InfiniteGridSizeInteractor(infiniteGridSizeRepository) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt new file mode 100644 index 000000000000..e3beff727ae3 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/domain/interactor/NoopGridConsistencyInteractorKosmos.kt @@ -0,0 +1,21 @@ +/* + * 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.qs.panels.domain.interactor + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.noopGridConsistencyInteractor by Kosmos.Fixture { NoopGridConsistencyInteractor() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt index 5fd876222852..9481fcac97d6 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/panels/ui/viewmodel/TileGridViewModelKosmos.kt @@ -20,8 +20,7 @@ import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.qs.panels.domain.interactor.gridLayoutMap import com.android.systemui.qs.panels.domain.interactor.gridLayoutTypeInteractor -import com.android.systemui.qs.panels.domain.interactor.iconTilesInteractor -import com.android.systemui.qs.panels.ui.compose.InfiniteGridLayout +import com.android.systemui.qs.panels.domain.interactor.infiniteGridLayout import com.android.systemui.qs.pipeline.domain.interactor.currentTilesInteractor val Kosmos.tileGridViewModel by @@ -30,7 +29,7 @@ val Kosmos.tileGridViewModel by gridLayoutTypeInteractor, gridLayoutMap, currentTilesInteractor, - InfiniteGridLayout(iconTilesInteractor), + infiniteGridLayout, applicationCoroutineScope, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorKosmos.kt new file mode 100644 index 000000000000..d10780b6b817 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/pipeline/domain/interactor/PanelInteractorKosmos.kt @@ -0,0 +1,22 @@ +/* + * 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.qs.pipeline.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.shade.shadeController + +val Kosmos.panelInteractor by Kosmos.Fixture { PanelInteractorImpl(shadeController) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt index 5c4b39081143..419e7810b604 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/di/NewQSTileFactoryKosmos.kt @@ -16,23 +16,63 @@ package com.android.systemui.qs.tiles.di +import android.os.UserHandle import com.android.systemui.kosmos.Kosmos +import com.android.systemui.qs.instanceIdSequenceFake +import com.android.systemui.qs.pipeline.shared.TileSpec +import com.android.systemui.qs.tiles.base.viewmodel.QSTileViewModelFactory +import com.android.systemui.qs.tiles.viewmodel.QSTileConfig +import com.android.systemui.qs.tiles.viewmodel.QSTileState +import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig +import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel import com.android.systemui.qs.tiles.viewmodel.qSTileConfigProvider import com.android.systemui.qs.tiles.viewmodel.qsTileViewModelAdaperFactory +import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.mock +import com.android.systemui.util.mockito.whenever import javax.inject.Provider -import org.mockito.Mockito +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow +import kotlinx.coroutines.flow.StateFlow var Kosmos.newFactoryTileMap by Kosmos.Fixture { emptyMap<String, Provider<QSTileViewModel>>() } +val Kosmos.customTileViewModelFactory: QSTileViewModelFactory.Component by + Kosmos.Fixture { + mock { + whenever(create(any())).thenAnswer { invocation -> + val tileSpec = invocation.getArgument<TileSpec>(0) + val config = + QSTileConfig( + tileSpec, + QSTileUIConfig.Empty, + instanceIdSequenceFake.newInstanceId(), + ) + object : QSTileViewModel { + override val state: SharedFlow<QSTileState> = + MutableStateFlow(QSTileState.build({ null }, tileSpec.spec) {}) + override val config: QSTileConfig = config + override val isAvailable: StateFlow<Boolean> = MutableStateFlow(true) + + override fun onUserChanged(user: UserHandle) {} + + override fun forceUpdate() {} + + override fun onActionPerformed(userAction: QSTileUserAction) {} + + override fun destroy() {} + } + } + } + } + val Kosmos.newQSTileFactory by Kosmos.Fixture { NewQSTileFactory( qSTileConfigProvider, qsTileViewModelAdaperFactory, newFactoryTileMap, - mock(Mockito.withSettings().defaultAnswer(Mockito.RETURNS_MOCKS)), - mock(Mockito.withSettings().defaultAnswer(Mockito.RETURNS_MOCKS)), + customTileViewModelFactory, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/CustomTileKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/CustomTileKosmos.kt index 561e2540d465..42437d5a5b81 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/CustomTileKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/CustomTileKosmos.kt @@ -23,6 +23,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.activityStarter import com.android.systemui.qs.external.FakeCustomTileStatePersister import com.android.systemui.qs.external.tileServices +import com.android.systemui.qs.external.tileServicesFacade import com.android.systemui.qs.pipeline.shared.TileSpec import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler import com.android.systemui.qs.tiles.base.logging.QSTileLogger @@ -38,10 +39,10 @@ import com.android.systemui.qs.tiles.viewmodel.QSTileConfigTestBuilder import com.android.systemui.user.data.repository.userRepository import com.android.systemui.util.mockito.mock -var Kosmos.tileSpec: TileSpec.CustomTileSpec by Kosmos.Fixture() +var Kosmos.customTileSpec: TileSpec.CustomTileSpec by Kosmos.Fixture() var Kosmos.customTileQsTileConfig: QSTileConfig by - Kosmos.Fixture { QSTileConfigTestBuilder.build { tileSpec = this@Fixture.tileSpec } } + Kosmos.Fixture { QSTileConfigTestBuilder.build { tileSpec = this@Fixture.customTileSpec } } val Kosmos.qsTileLogger: QSTileLogger by Kosmos.Fixture { mock {} } val Kosmos.customTileStatePersister: FakeCustomTileStatePersister by @@ -50,7 +51,7 @@ val Kosmos.customTileStatePersister: FakeCustomTileStatePersister by val Kosmos.customTileInteractor: CustomTileInteractor by Kosmos.Fixture { CustomTileInteractor( - tileSpec, + customTileSpec, customTileDefaultsRepository, customTileRepository, testScope.backgroundScope, @@ -61,7 +62,7 @@ val Kosmos.customTileInteractor: CustomTileInteractor by val Kosmos.customTileRepository: FakeCustomTileRepository by Kosmos.Fixture { FakeCustomTileRepository( - tileSpec, + customTileSpec, customTileStatePersister, packageManagerAdapterFacade, testScope.testScheduler, @@ -75,18 +76,18 @@ val Kosmos.customTilePackagesUpdatesRepository: FakeCustomTilePackageUpdatesRepo Kosmos.Fixture { FakeCustomTilePackageUpdatesRepository() } val Kosmos.packageManagerAdapterFacade: FakePackageManagerAdapterFacade by - Kosmos.Fixture { FakePackageManagerAdapterFacade(tileSpec.componentName) } + Kosmos.Fixture { FakePackageManagerAdapterFacade(customTileSpec.componentName) } val Kosmos.customTileServiceInteractor: CustomTileServiceInteractor by Kosmos.Fixture { CustomTileServiceInteractor( - tileSpec, + customTileSpec, activityStarter, { customTileUserActionInteractor }, customTileInteractor, userRepository, qsTileLogger, - tileServices, + tileServicesFacade.tileServices, testScope.backgroundScope, ) } @@ -95,7 +96,7 @@ val Kosmos.customTileUserActionInteractor: CustomTileUserActionInteractor by Kosmos.Fixture { CustomTileUserActionInteractor( testCase.context, - tileSpec, + customTileSpec, qsTileLogger, mock {}, mock {}, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakePackageManagerAdapterFacade.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakePackageManagerAdapterFacade.kt index 634d121a556c..fa8d36366415 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakePackageManagerAdapterFacade.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/custom/data/repository/FakePackageManagerAdapterFacade.kt @@ -17,6 +17,7 @@ package com.android.systemui.qs.tiles.impl.custom.data.repository import android.content.ComponentName +import android.content.pm.PackageInfo import android.content.pm.ServiceInfo import android.os.Bundle import com.android.systemui.qs.external.PackageManagerAdapter @@ -24,6 +25,7 @@ import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever +import org.mockito.ArgumentMatchers.anyInt /** * Facade for [PackageManagerAdapter] to provide a fake-like behaviour. You can create this class @@ -45,19 +47,33 @@ class FakePackageManagerAdapterFacade( init { whenever(packageManagerAdapter.getServiceInfo(eq(componentName), any())).thenAnswer { - ServiceInfo().apply { - metaData = - Bundle().apply { - putBoolean( - android.service.quicksettings.TileService.META_DATA_TOGGLEABLE_TILE, - isToggleable - ) - putBoolean( - android.service.quicksettings.TileService.META_DATA_ACTIVE_TILE, - isActive - ) - } - } + createServiceInfo() + } + whenever( + packageManagerAdapter.getPackageInfoAsUser( + eq(componentName.packageName), + anyInt(), + anyInt() + ) + ) + .thenAnswer { PackageInfo().apply { packageName = componentName.packageName } } + whenever(packageManagerAdapter.getServiceInfo(eq(componentName), anyInt(), anyInt())) + .thenAnswer { createServiceInfo() } + } + + private fun createServiceInfo(): ServiceInfo { + return ServiceInfo().apply { + metaData = + Bundle().apply { + putBoolean( + android.service.quicksettings.TileService.META_DATA_TOGGLEABLE_TILE, + isToggleable + ) + putBoolean( + android.service.quicksettings.TileService.META_DATA_ACTIVE_TILE, + isActive + ) + } } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt new file mode 100644 index 000000000000..3bb9580e69fa --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryKosmos.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.phone + +import android.content.applicationContext +import com.android.systemui.animation.dialogTransitionAnimator +import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.model.sysUiState + +val Kosmos.systemUIDialogFactory by + Kosmos.Fixture { + SystemUIDialogFactory( + applicationContext, + systemUIDialogManager, + sysUiState, + broadcastDispatcher, + dialogTransitionAnimator, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/MockExecutorHandler.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/MockExecutorHandler.kt index 184d4b53f2f8..92f9248b2935 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/MockExecutorHandler.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/concurrency/MockExecutorHandler.kt @@ -17,6 +17,8 @@ package com.android.systemui.util.concurrency import android.os.Handler +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.Executor import org.mockito.ArgumentMatchers.any import org.mockito.ArgumentMatchers.anyLong @@ -29,9 +31,14 @@ import org.mockito.stubbing.Answer * Wrap an [Executor] in a mock [Handler] that execute when [Handler.post] is called, and throws an * exception otherwise. This is useful when a class requires a Handler only because Handlers are * used by ContentObserver, and no other methods are used. + * + * If the [executor] is a [DelayableExecutor], it also supports: + * * [Handler.postDelayed] with a Runnable parameter + * * [Handler.postAtTime] with a RunnableParameter */ fun mockExecutorHandler(executor: Executor): Handler { val handlerMock = Mockito.mock(Handler::class.java, RuntimeExceptionAnswer()) + val cancellations = ConcurrentHashMap<Runnable, MutableList<Cancellation>>() doAnswer { invocation: InvocationOnMock -> executor.execute(invocation.getArgument(0)) true @@ -42,7 +49,19 @@ fun mockExecutorHandler(executor: Executor): Handler { doAnswer { invocation: InvocationOnMock -> val runnable = invocation.getArgument<Runnable>(0) val uptimeMillis = invocation.getArgument<Long>(1) - executor.executeAtTime(runnable, uptimeMillis) + val token = Any() + val canceller = + executor.executeAtTime( + { + cancellations.get(runnable)?.removeIf { it.token == token } + cancellations.remove(runnable, emptyList()) + runnable.run() + }, + uptimeMillis + ) + cancellations + .getOrPut(runnable) { CopyOnWriteArrayList() } + .add(Cancellation(token, canceller)) true } .`when`(handlerMock) @@ -50,15 +69,36 @@ fun mockExecutorHandler(executor: Executor): Handler { doAnswer { invocation: InvocationOnMock -> val runnable = invocation.getArgument<Runnable>(0) val delayInMillis = invocation.getArgument<Long>(1) - executor.executeDelayed(runnable, delayInMillis) + val token = Any() + val canceller = + executor.executeDelayed( + { + cancellations.get(runnable)?.removeIf { it.token == token } + cancellations.remove(runnable, emptyList()) + runnable.run() + }, + delayInMillis + ) + cancellations + .getOrPut(runnable) { CopyOnWriteArrayList() } + .add(Cancellation(token, canceller)) true } .`when`(handlerMock) .postDelayed(any(), anyLong()) + doAnswer { invocation: InvocationOnMock -> + val runnable = invocation.getArgument<Runnable>(0) + cancellations.remove(runnable)?.forEach(Runnable::run) + Unit + } + .`when`(handlerMock) + .removeCallbacks(any()) } return handlerMock } +private class Cancellation(val token: Any, canceller: Runnable) : Runnable by canceller + private class RuntimeExceptionAnswer : Answer<Any> { override fun answer(invocation: InvocationOnMock): Any { throw RuntimeException(invocation.method.name + " is not stubbed") diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt index d74355894581..59bbff171725 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/MediaOutputKosmos.kt @@ -19,9 +19,8 @@ package com.android.systemui.volume import android.content.packageManager import android.content.pm.ApplicationInfo import android.os.Handler -import android.testing.TestableLooper +import android.os.looper import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.testCase import com.android.systemui.kosmos.testScope import com.android.systemui.media.mediaOutputDialogManager import com.android.systemui.util.mockito.any @@ -54,7 +53,7 @@ val Kosmos.mediaOutputInteractor by testScope.backgroundScope, testScope.testScheduler, mediaControllerRepository, - Handler(TestableLooper.get(testCase).looper), + Handler(looper), ) } @@ -62,7 +61,7 @@ val Kosmos.mediaDeviceSessionInteractor by Kosmos.Fixture { MediaDeviceSessionInteractor( testScope.testScheduler, - Handler(TestableLooper.get(testCase).looper), + Handler(looper), mediaControllerRepository, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorKosmos.kt new file mode 100644 index 000000000000..d1d873ee1082 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/domain/interactor/AudioVolumeInteractorKosmos.kt @@ -0,0 +1,30 @@ +/* + * 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.volume.domain.interactor + +import com.android.settingslib.volume.domain.interactor.AudioVolumeInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.statusbar.notification.domain.interactor.notificationsSoundPolicyInteractor +import com.android.systemui.volume.data.repository.audioRepository + +val Kosmos.audioVolumeInteractor by + Kosmos.Fixture { + AudioVolumeInteractor( + audioRepository, + notificationsSoundPolicyInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt deleted file mode 100644 index 146f1093fe69..000000000000 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/VolumePanelKosmos.kt +++ /dev/null @@ -1,78 +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.volume.panel - -import android.content.res.mainResources -import com.android.systemui.broadcast.broadcastDispatcher -import com.android.systemui.kosmos.Kosmos -import com.android.systemui.kosmos.testScope -import com.android.systemui.statusbar.policy.fakeConfigurationController -import com.android.systemui.util.mockito.mock -import com.android.systemui.volume.panel.dagger.factory.KosmosVolumePanelComponentFactory -import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria -import com.android.systemui.volume.panel.domain.TestComponentAvailabilityCriteria -import com.android.systemui.volume.panel.domain.VolumePanelStartable -import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractor -import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractorImpl -import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey -import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent -import com.android.systemui.volume.panel.ui.composable.ComponentsFactory -import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager -import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel -import javax.inject.Provider - -val Kosmos.mockVolumePanelUiComponent: VolumePanelUiComponent by Kosmos.Fixture { mock {} } -val Kosmos.mockVolumePanelUiComponentProvider: Provider<VolumePanelUiComponent> by - Kosmos.Fixture { Provider { mockVolumePanelUiComponent } } -var Kosmos.componentByKey: Map<VolumePanelComponentKey, Provider<VolumePanelUiComponent>> by - Kosmos.Fixture { emptyMap() } -val Kosmos.componentsFactory: ComponentsFactory by - Kosmos.Fixture { ComponentsFactory(componentByKey) } - -var Kosmos.componentsLayoutManager: ComponentsLayoutManager by Kosmos.Fixture() -var Kosmos.enabledComponents: Collection<VolumePanelComponentKey> by - Kosmos.Fixture { componentByKey.keys } -var Kosmos.volumePanelStartables: Set<VolumePanelStartable> by - Kosmos.Fixture { emptySet<VolumePanelStartable>() } -val Kosmos.unavailableCriteria: Provider<ComponentAvailabilityCriteria> by - Kosmos.Fixture { Provider { TestComponentAvailabilityCriteria(false) } } -val Kosmos.availableCriteria: Provider<ComponentAvailabilityCriteria> by - Kosmos.Fixture { Provider { TestComponentAvailabilityCriteria(true) } } -var Kosmos.defaultCriteria: Provider<ComponentAvailabilityCriteria> by - Kosmos.Fixture { availableCriteria } -var Kosmos.criteriaByKey: Map<VolumePanelComponentKey, Provider<ComponentAvailabilityCriteria>> by - Kosmos.Fixture { emptyMap() } -var Kosmos.componentsInteractor: ComponentsInteractor by - Kosmos.Fixture { - ComponentsInteractorImpl( - enabledComponents, - defaultCriteria, - testScope.backgroundScope, - criteriaByKey, - ) - } - -var Kosmos.volumePanelViewModel: VolumePanelViewModel by - Kosmos.Fixture { - VolumePanelViewModel( - mainResources, - testScope.backgroundScope, - KosmosVolumePanelComponentFactory(this), - fakeConfigurationController, - broadcastDispatcher, - ) - } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponentKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponentKosmos.kt new file mode 100644 index 000000000000..2ea27c7e32de --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/bottombar/ui/BottomBarComponentKosmos.kt @@ -0,0 +1,26 @@ +/* + * 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.volume.panel.component.bottombar.ui + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.volume.panel.component.bottombar.ui.viewmodel.bottomBarViewModel +import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria +import com.android.systemui.volume.panel.domain.availableCriteria + +var Kosmos.bottomBarComponent by Kosmos.Fixture { BottomBarComponent(bottomBarViewModel) } +var Kosmos.bottomBarAvailabilityCriteria: ComponentAvailabilityCriteria by + Kosmos.Fixture { availableCriteria } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelKosmos.kt new file mode 100644 index 000000000000..128ede1f8108 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/bottombar/ui/viewmodel/BottomBarViewModelKosmos.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.bottombar.ui.viewmodel + +import com.android.internal.logging.uiEventLogger +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.plugins.activityStarter +import com.android.systemui.volume.panel.ui.viewmodel.volumePanelViewModel + +var Kosmos.bottomBarViewModel: BottomBarViewModel by + Kosmos.Fixture { + BottomBarViewModel( + activityStarter, + volumePanelViewModel, + uiEventLogger, + ) + } 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 new file mode 100644 index 000000000000..0c814c566d63 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/MediaOutputModuleKosmos.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.mediaoutput + +import com.android.systemui.kosmos.Kosmos +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 } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelKosmos.kt new file mode 100644 index 000000000000..6d4576efd34c --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/mediaoutput/ui/viewmodel/MediaOutputViewModelKosmos.kt @@ -0,0 +1,41 @@ +/* + * 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.volume.panel.component.mediaoutput.ui.viewmodel + +import android.content.applicationContext +import com.android.internal.logging.uiEventLogger +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.volume.domain.interactor.audioModeInteractor +import com.android.systemui.volume.domain.interactor.audioOutputInteractor +import com.android.systemui.volume.mediaDeviceSessionInteractor +import com.android.systemui.volume.mediaOutputActionsInteractor +import com.android.systemui.volume.mediaOutputInteractor + +var Kosmos.mediaOutputViewModel by + Kosmos.Fixture { + MediaOutputViewModel( + applicationContext, + testScope.backgroundScope, + mediaOutputActionsInteractor, + mediaDeviceSessionInteractor, + audioOutputInteractor, + audioModeInteractor, + mediaOutputInteractor, + uiEventLogger, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/VolumeModuleKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/VolumeModuleKosmos.kt new file mode 100644 index 000000000000..a17e7454ed65 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/VolumeModuleKosmos.kt @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.volume + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.volume.panel.component.volume.ui.composable.VolumeSlidersComponent +import com.android.systemui.volume.panel.component.volume.ui.viewmodel.audioVolumeComponentViewModel +import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria +import com.android.systemui.volume.panel.domain.availableCriteria + +var Kosmos.volumeSlidersComponent: VolumeSlidersComponent by + Kosmos.Fixture { VolumeSlidersComponent(audioVolumeComponentViewModel) } +var Kosmos.volumeSlidersAvailabilityCriteria: ComponentAvailabilityCriteria by + Kosmos.Fixture { availableCriteria } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt new file mode 100644 index 000000000000..a0a39d14dcf6 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/domain/interactor/AudioSlidersInteractorKosmos.kt @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.volume.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.volume.data.repository.audioRepository +import com.android.systemui.volume.mediaOutputInteractor + +val Kosmos.audioSlidersInteractor by + Kosmos.Fixture { + AudioSlidersInteractor( + testScope.backgroundScope, + mediaOutputInteractor, + audioRepository, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt new file mode 100644 index 000000000000..b2b19de654b6 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/AudioStreamSliderViewModelKosmos.kt @@ -0,0 +1,42 @@ +/* + * 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.volume.panel.component.volume.slider.ui.viewmodel + +import android.content.applicationContext +import com.android.internal.logging.uiEventLogger +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.volume.domain.interactor.audioVolumeInteractor +import kotlinx.coroutines.CoroutineScope + +val Kosmos.audioStreamSliderViewModelFactory by + Kosmos.Fixture { + object : AudioStreamSliderViewModel.Factory { + + override fun create( + audioStream: AudioStreamSliderViewModel.FactoryAudioStreamWrapper, + coroutineScope: CoroutineScope, + ): AudioStreamSliderViewModel { + return AudioStreamSliderViewModel( + audioStream, + coroutineScope, + applicationContext, + audioVolumeInteractor, + uiEventLogger, + ) + } + } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt new file mode 100644 index 000000000000..f0cb2cd904ca --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/slider/ui/viewmodel/CastVolumeSliderViewModelKosmos.kt @@ -0,0 +1,40 @@ +/* + * 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.volume.panel.component.volume.slider.ui.viewmodel + +import android.content.applicationContext +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.volume.mediaDeviceSessionInteractor +import com.android.systemui.volume.panel.component.mediaoutput.shared.model.MediaDeviceSession +import kotlinx.coroutines.CoroutineScope + +val Kosmos.castVolumeSliderViewModelFactory by + Kosmos.Fixture { + object : CastVolumeSliderViewModel.Factory { + override fun create( + session: MediaDeviceSession, + coroutineScope: CoroutineScope + ): CastVolumeSliderViewModel { + return CastVolumeSliderViewModel( + session, + coroutineScope, + applicationContext, + mediaDeviceSessionInteractor, + ) + } + } + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/VolumeSlidersViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/VolumeSlidersViewModelKosmos.kt new file mode 100644 index 000000000000..45a291e0e401 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/component/volume/ui/viewmodel/VolumeSlidersViewModelKosmos.kt @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.volume.panel.component.volume.ui.viewmodel + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.volume.mediaDeviceSessionInteractor +import com.android.systemui.volume.mediaOutputInteractor +import com.android.systemui.volume.panel.component.volume.domain.interactor.audioSlidersInteractor +import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.audioStreamSliderViewModelFactory +import com.android.systemui.volume.panel.component.volume.slider.ui.viewmodel.castVolumeSliderViewModelFactory + +val Kosmos.audioVolumeComponentViewModel by + Kosmos.Fixture { + AudioVolumeComponentViewModel( + testScope.backgroundScope, + mediaOutputInteractor, + mediaDeviceSessionInteractor, + audioStreamSliderViewModelFactory, + castVolumeSliderViewModelFactory, + audioSlidersInteractor, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt index 1e895b5ed4de..587a7ea589bc 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/KosmosVolumePanelComponentFactory.kt @@ -18,16 +18,16 @@ package com.android.systemui.volume.panel.dagger.factory import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.testScope -import com.android.systemui.volume.panel.componentsFactory -import com.android.systemui.volume.panel.componentsInteractor -import com.android.systemui.volume.panel.componentsLayoutManager import com.android.systemui.volume.panel.dagger.VolumePanelComponent import com.android.systemui.volume.panel.domain.VolumePanelStartable import com.android.systemui.volume.panel.domain.interactor.ComponentsInteractor +import com.android.systemui.volume.panel.domain.interactor.componentsInteractor import com.android.systemui.volume.panel.ui.composable.ComponentsFactory +import com.android.systemui.volume.panel.ui.composable.componentsFactory import com.android.systemui.volume.panel.ui.layout.ComponentsLayoutManager +import com.android.systemui.volume.panel.ui.layout.componentsLayoutManager import com.android.systemui.volume.panel.ui.viewmodel.VolumePanelViewModel -import com.android.systemui.volume.panel.volumePanelStartables +import com.android.systemui.volume.panel.ui.viewmodel.volumePanelStartables import kotlinx.coroutines.CoroutineScope class KosmosVolumePanelComponentFactory(private val kosmos: Kosmos) : VolumePanelComponentFactory { diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/VolumePanelComponentFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/VolumePanelComponentFactoryKosmos.kt new file mode 100644 index 000000000000..b0b06f1935f9 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/dagger/factory/VolumePanelComponentFactoryKosmos.kt @@ -0,0 +1,21 @@ +/* + * 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.volume.panel.dagger.factory + +import com.android.systemui.kosmos.Kosmos + +var Kosmos.volumePanelComponentFactory by Kosmos.Fixture { KosmosVolumePanelComponentFactory(this) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/ComponentAvailabilityCriteriaKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/ComponentAvailabilityCriteriaKosmos.kt new file mode 100644 index 000000000000..e0547eed75e9 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/ComponentAvailabilityCriteriaKosmos.kt @@ -0,0 +1,25 @@ +/* + * 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.volume.panel.domain + +import com.android.systemui.kosmos.Kosmos + +val Kosmos.unavailableCriteria: ComponentAvailabilityCriteria by + Kosmos.Fixture { TestComponentAvailabilityCriteria(false) } +val Kosmos.availableCriteria: ComponentAvailabilityCriteria by + Kosmos.Fixture { AlwaysAvailableCriteria() } +var Kosmos.defaultCriteria: ComponentAvailabilityCriteria by Kosmos.Fixture { availableCriteria } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorKosmos.kt new file mode 100644 index 000000000000..8862942aa083 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/domain/interactor/ComponentsInteractorKosmos.kt @@ -0,0 +1,51 @@ +/* + * 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.volume.panel.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.volume.panel.component.bottombar.ui.bottomBarAvailabilityCriteria +import com.android.systemui.volume.panel.component.mediaoutput.mediaOutputAvailabilityCriteria +import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents +import com.android.systemui.volume.panel.component.volume.volumeSlidersAvailabilityCriteria +import com.android.systemui.volume.panel.domain.ComponentAvailabilityCriteria +import com.android.systemui.volume.panel.domain.defaultCriteria +import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey +import com.android.systemui.volume.panel.ui.composable.enabledComponents +import javax.inject.Provider + +var Kosmos.criteriaByKey: Map<VolumePanelComponentKey, Provider<ComponentAvailabilityCriteria>> by + Kosmos.Fixture { emptyMap() } +var Kosmos.prodCriteriaByKey: + Map<VolumePanelComponentKey, Provider<ComponentAvailabilityCriteria>> by + Kosmos.Fixture { + mapOf( + VolumePanelComponents.MEDIA_OUTPUT to Provider { mediaOutputAvailabilityCriteria }, + VolumePanelComponents.VOLUME_SLIDERS to Provider { volumeSlidersAvailabilityCriteria }, + VolumePanelComponents.BOTTOM_BAR to Provider { bottomBarAvailabilityCriteria }, + ) + } + +var Kosmos.componentsInteractor: ComponentsInteractor by + Kosmos.Fixture { + ComponentsInteractorImpl( + enabledComponents, + { defaultCriteria }, + testScope.backgroundScope, + criteriaByKey, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/shared/model/VolumePanelUiComponentKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/shared/model/VolumePanelUiComponentKosmos.kt new file mode 100644 index 000000000000..afe8e622eee6 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/shared/model/VolumePanelUiComponentKosmos.kt @@ -0,0 +1,25 @@ +/* + * 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.volume.panel.shared.model + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock +import javax.inject.Provider + +val Kosmos.mockVolumePanelUiComponent: VolumePanelUiComponent by Kosmos.Fixture { mock {} } +val Kosmos.mockVolumePanelUiComponentProvider: Provider<VolumePanelUiComponent> by + Kosmos.Fixture { Provider { mock {} } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryKosmos.kt new file mode 100644 index 000000000000..bacf22c0fef6 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/composable/ComponentsFactoryKosmos.kt @@ -0,0 +1,42 @@ +/* + * 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.volume.panel.ui.composable + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.volume.panel.component.bottombar.ui.bottomBarComponent +import com.android.systemui.volume.panel.component.mediaoutput.mediaOutputComponent +import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents +import com.android.systemui.volume.panel.component.volume.volumeSlidersComponent +import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey +import com.android.systemui.volume.panel.shared.model.VolumePanelUiComponent +import javax.inject.Provider + +var Kosmos.componentByKey: Map<VolumePanelComponentKey, Provider<VolumePanelUiComponent>> by + Kosmos.Fixture { emptyMap() } +var Kosmos.prodComponentByKey: Map<VolumePanelComponentKey, Provider<VolumePanelUiComponent>> by + Kosmos.Fixture { + mapOf( + VolumePanelComponents.BOTTOM_BAR to Provider { bottomBarComponent }, + VolumePanelComponents.MEDIA_OUTPUT to Provider { mediaOutputComponent }, + VolumePanelComponents.VOLUME_SLIDERS to Provider { volumeSlidersComponent }, + ) + } +var Kosmos.enabledComponents: Collection<VolumePanelComponentKey> by + Kosmos.Fixture { componentByKey.keys } + +val Kosmos.componentsFactory: ComponentsFactory by + Kosmos.Fixture { ComponentsFactory(componentByKey) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/ComponentsLayoutManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/ComponentsLayoutManagerKosmos.kt new file mode 100644 index 000000000000..e0480e7cf986 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/layout/ComponentsLayoutManagerKosmos.kt @@ -0,0 +1,43 @@ +/* + * 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.volume.panel.ui.layout + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.volume.panel.component.shared.model.VolumePanelComponents +import com.android.systemui.volume.panel.shared.model.VolumePanelComponentKey + +var Kosmos.volumePanelBottomBarComponentKey: VolumePanelComponentKey by + Kosmos.Fixture { VolumePanelComponents.BOTTOM_BAR } +var Kosmos.volumePanelHeaderComponentKeys: Collection<VolumePanelComponentKey> by + Kosmos.Fixture { listOf(VolumePanelComponents.MEDIA_OUTPUT) } +var Kosmos.volumePanelFooterComponentKeys: Collection<VolumePanelComponentKey> by + Kosmos.Fixture { + listOf( + VolumePanelComponents.ANC, + VolumePanelComponents.SPATIAL_AUDIO, + VolumePanelComponents.CAPTIONING, + ) + } + +var Kosmos.componentsLayoutManager: ComponentsLayoutManager by + Kosmos.Fixture { + DefaultComponentsLayoutManager( + bottomBar = volumePanelBottomBarComponentKey, + headerComponents = volumePanelHeaderComponentKeys, + footerComponents = volumePanelFooterComponentKeys, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelKosmos.kt new file mode 100644 index 000000000000..a60658830be4 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/panel/ui/viewmodel/VolumePanelViewModelKosmos.kt @@ -0,0 +1,40 @@ +/* + * 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.volume.panel.ui.viewmodel + +import android.content.applicationContext +import com.android.systemui.broadcast.broadcastDispatcher +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.policy.configurationController +import com.android.systemui.volume.panel.dagger.factory.volumePanelComponentFactory +import com.android.systemui.volume.panel.domain.VolumePanelStartable + +var Kosmos.volumePanelStartables: Set<VolumePanelStartable> by Kosmos.Fixture { emptySet() } + +var Kosmos.volumePanelViewModel: VolumePanelViewModel by + Kosmos.Fixture { volumePanelViewModelFactory.create(testScope.backgroundScope) } + +val Kosmos.volumePanelViewModelFactory: VolumePanelViewModel.Factory by + Kosmos.Fixture { + VolumePanelViewModel.Factory( + applicationContext, + volumePanelComponentFactory, + configurationController, + broadcastDispatcher, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/ui/navigation/VolumeNavigatorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/ui/navigation/VolumeNavigatorKosmos.kt new file mode 100644 index 000000000000..63b3f237a953 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/ui/navigation/VolumeNavigatorKosmos.kt @@ -0,0 +1,40 @@ +/* + * 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.volume.ui.navigation + +import com.android.internal.logging.uiEventLoggerFake +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.mainCoroutineContext +import com.android.systemui.kosmos.testScope +import com.android.systemui.plugins.activityStarter +import com.android.systemui.statusbar.phone.systemUIDialogFactory +import com.android.systemui.util.mockito.mock +import com.android.systemui.volume.VolumePanelFactory +import com.android.systemui.volume.panel.ui.viewmodel.volumePanelViewModelFactory + +val Kosmos.volumeNavigator by + Kosmos.Fixture { + VolumeNavigator( + testScope, + mainCoroutineContext, + mock<VolumePanelFactory> { /* Unsupported and unused */}, + activityStarter, + volumePanelViewModelFactory, + systemUIDialogFactory, + uiEventLoggerFake, + ) + } diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index bc608c5ac0c0..95cbb6b2130a 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -221,7 +221,9 @@ sh_test_host { data: [ ":framework-minus-apex.ravenwood.stats", ":framework-minus-apex.ravenwood.apis", + ":framework-minus-apex.ravenwood.keep_all", ":services.core.ravenwood.stats", ":services.core.ravenwood.apis", + ":services.core.ravenwood.keep_all", ], } diff --git a/ravenwood/scripts/ravenwood-stats-collector.sh b/ravenwood/scripts/ravenwood-stats-collector.sh index cf58bd2f3717..43b61a46b747 100755 --- a/ravenwood/scripts/ravenwood-stats-collector.sh +++ b/ravenwood/scripts/ravenwood-stats-collector.sh @@ -18,8 +18,14 @@ set -e # Output files -stats=/tmp/ravenwood-stats-all.csv -apis=/tmp/ravenwood-apis-all.csv +out_dir=/tmp/ravenwood +stats=$out_dir/ravenwood-stats-all.csv +apis=$out_dir/ravenwood-apis-all.csv +keep_all_dir=$out_dir/ravenwood-keep-all/ + +rm -fr $out_dir +mkdir -p $out_dir +mkdir -p $keep_all_dir # Where the input files are. path=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/ravenwood-stats-checker/x86_64/ @@ -76,3 +82,7 @@ collect_apis() { collect_stats $stats collect_apis $apis + +cp *keep_all.txt $keep_all_dir +echo "Keep all files created at:" +find $keep_all_dir -type f
\ No newline at end of file diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 249b3cb71c2e..71b16c3a18b6 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -172,8 +172,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku OnCrossProfileWidgetProvidersChangeListener { private static final String TAG = "AppWidgetServiceImpl"; - private static final boolean DEBUG = false; - private static final boolean DEBUG_NULL_PROVIDER_INFO = Build.IS_DEBUGGABLE; + private static final boolean DEBUG = Build.IS_DEBUGGABLE; private static final String OLD_KEYGUARD_HOST_PACKAGE = "android"; private static final String NEW_KEYGUARD_HOST_PACKAGE = "com.android.keyguard"; @@ -1573,9 +1572,36 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku Binder.getCallingUid(), callingPackage); if (widget != null && widget.provider != null && !widget.provider.zombie) { - return cloneIfLocalBinder(widget.provider.getInfoLocked(mContext)); + final AppWidgetProviderInfo info = widget.provider.getInfoLocked(mContext); + if (info == null) { + Slog.e(TAG, "getAppWidgetInfo() returns null because" + + " widget.provider.getInfoLocked() returned null." + + " appWidgetId=" + appWidgetId + " userId=" + userId + + " widget=" + widget); + return null; + } + final AppWidgetProviderInfo ret = cloneIfLocalBinder(info); + if (ret == null) { + Slog.e(TAG, "getAppWidgetInfo() returns null because" + + " cloneIfLocalBinder() returned null." + + " appWidgetId=" + appWidgetId + " userId=" + userId + + " widget=" + widget + " appWidgetProviderInfo=" + info); + } + return ret; + } else { + if (widget == null) { + Slog.e(TAG, "getAppWidgetInfo() returns null because widget is null." + + " appWidgetId=" + appWidgetId + " userId=" + userId); + } else if (widget.provider == null) { + Slog.e(TAG, "getAppWidgetInfo() returns null because widget.provider is null." + + " appWidgetId=" + appWidgetId + " userId=" + userId + + " widget=" + widget); + } else { + Slog.e(TAG, "getAppWidgetInfo() returns null because widget.provider is zombie." + + " appWidgetId=" + appWidgetId + " userId=" + userId + + " widget=" + widget); + } } - return null; } } @@ -2960,7 +2986,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku AppWidgetProviderInfo info = new AppWidgetProviderInfo(); info.provider = providerId.componentName; info.providerInfo = ri.activityInfo; - if (DEBUG_NULL_PROVIDER_INFO) { + if (DEBUG) { Objects.requireNonNull(ri.activityInfo); } return info; @@ -2997,7 +3023,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku AppWidgetProviderInfo info = new AppWidgetProviderInfo(); info.provider = providerId.componentName; info.providerInfo = activityInfo; - if (DEBUG_NULL_PROVIDER_INFO) { + if (DEBUG) { Objects.requireNonNull(activityInfo); } @@ -3575,7 +3601,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku AppWidgetProviderInfo info = new AppWidgetProviderInfo(); info.provider = providerId.componentName; info.providerInfo = providerInfo; - if (DEBUG_NULL_PROVIDER_INFO) { + if (DEBUG) { Objects.requireNonNull(providerInfo); } @@ -3594,7 +3620,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (info != null) { info.provider = providerId.componentName; info.providerInfo = providerInfo; - if (DEBUG_NULL_PROVIDER_INFO) { + if (DEBUG) { Objects.requireNonNull(providerInfo); } provider.setInfoLocked(info); @@ -4678,6 +4704,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } if (newInfo != null) { info = newInfo; + if (DEBUG) { + Objects.requireNonNull(info); + } updateGeneratedPreviewCategoriesLocked(); } } @@ -4699,12 +4728,18 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku @GuardedBy("AppWidgetServiceImpl.mLock") public void setPartialInfoLocked(AppWidgetProviderInfo info) { this.info = info; + if (DEBUG) { + Objects.requireNonNull(this.info); + } mInfoParsed = false; } @GuardedBy("AppWidgetServiceImpl.mLock") public void setInfoLocked(AppWidgetProviderInfo info) { this.info = info; + if (DEBUG) { + Objects.requireNonNull(this.info); + } mInfoParsed = true; } @@ -5731,7 +5766,9 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // so we tear it down in anticipation of it (possibly) being // reconstructed due to the restore host.widgets.remove(widget); - provider.widgets.remove(widget); + if (provider != null) { + provider.widgets.remove(widget); + } // Check if we need to destroy any services (if no other app widgets are // referencing the same service) decrementAppWidgetServiceRefCount(widget); diff --git a/services/backup/java/com/android/server/backup/transport/TransportConnection.java b/services/backup/java/com/android/server/backup/transport/TransportConnection.java index 1009787bebe5..67ebb3e6a1ef 100644 --- a/services/backup/java/com/android/server/backup/transport/TransportConnection.java +++ b/services/backup/java/com/android/server/backup/transport/TransportConnection.java @@ -658,11 +658,13 @@ public class TransportConnection { * This class is a proxy to TransportClient methods that doesn't hold a strong reference to the * TransportClient, allowing it to be GC'ed. If the reference was lost it logs a message. */ - private static class TransportConnectionMonitor implements ServiceConnection { + @VisibleForTesting + static class TransportConnectionMonitor implements ServiceConnection { private final Context mContext; private final WeakReference<TransportConnection> mTransportClientRef; - private TransportConnectionMonitor(Context context, + @VisibleForTesting + TransportConnectionMonitor(Context context, TransportConnection transportConnection) { mContext = context; mTransportClientRef = new WeakReference<>(transportConnection); @@ -704,7 +706,13 @@ public class TransportConnection { /** @see TransportConnection#finalize() */ private void referenceLost(String caller) { - mContext.unbindService(this); + try { + mContext.unbindService(this); + } catch (IllegalArgumentException e) { + TransportUtils.log(Priority.WARN, TAG, + caller + " called but unbindService failed: " + e.getMessage()); + return; + } TransportUtils.log( Priority.INFO, TAG, diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java index 9069689ee5eb..026d29c9f821 100644 --- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java +++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java @@ -135,7 +135,7 @@ public class SystemDataTransferProcessor { */ public PendingIntent buildPermissionTransferUserConsentIntent(String packageName, @UserIdInt int userId, int associationId) { - if (PackageUtils.isPackageAllowlisted(mContext, mPackageManager, packageName)) { + if (PackageUtils.isPermSyncAutoEnabled(mContext, mPackageManager, packageName)) { Slog.i(LOG_TAG, "User consent Intent should be skipped. Returning null."); // Auto enable perm sync for the allowlisted packages, but don't override user decision PermissionSyncRequest request = getPermissionSyncRequest(associationId); diff --git a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java index 0e66fbc020a1..71a182225013 100644 --- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java +++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java @@ -23,6 +23,7 @@ import android.content.Context; import android.os.Build; import android.util.Slog; +import com.google.security.cryptauth.lib.securegcm.ukey2.AlertException; import com.google.security.cryptauth.lib.securegcm.ukey2.BadHandleException; import com.google.security.cryptauth.lib.securegcm.ukey2.CryptoException; import com.google.security.cryptauth.lib.securegcm.ukey2.D2DConnectionContextV1; @@ -203,7 +204,8 @@ public class SecureChannel { * * This method must only be called from one of the two participants. */ - public void establishSecureConnection() throws IOException, SecureChannelException { + public void establishSecureConnection() throws IOException, + SecureChannelException, HandshakeException { if (isSecured()) { Slog.d(TAG, "Channel is already secure."); return; @@ -334,7 +336,7 @@ public class SecureChannel { } } - private void initiateHandshake() throws IOException, BadHandleException { + private void initiateHandshake() throws IOException, BadHandleException , HandshakeException { if (mConnectionContext != null) { Slog.d(TAG, "Ukey2 handshake is already completed."); return; @@ -394,8 +396,8 @@ public class SecureChannel { } } - private void exchangeHandshake() - throws IOException, HandshakeException, BadHandleException, CryptoException { + private void exchangeHandshake() throws IOException, HandshakeException, + BadHandleException, CryptoException, AlertException { if (mConnectionContext != null) { Slog.d(TAG, "Ukey2 handshake is already completed."); return; diff --git a/services/companion/java/com/android/server/companion/utils/PackageUtils.java b/services/companion/java/com/android/server/companion/utils/PackageUtils.java index 254d28b1b2c2..94ab9dddd1f6 100644 --- a/services/companion/java/com/android/server/companion/utils/PackageUtils.java +++ b/services/companion/java/com/android/server/companion/utils/PackageUtils.java @@ -21,6 +21,11 @@ import static android.content.pm.PackageManager.GET_CONFIGURATIONS; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.os.Binder.getCallingUid; +import static com.android.internal.R.array.config_companionDeviceCerts; +import static com.android.internal.R.array.config_companionDevicePackages; +import static com.android.internal.R.array.config_companionPermSyncEnabledCerts; +import static com.android.internal.R.array.config_companionPermSyncEnabledPackages; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -185,15 +190,30 @@ public final class PackageUtils { */ public static boolean isPackageAllowlisted(Context context, PackageManagerInternal packageManagerInternal, @NonNull String packageName) { - final String[] allowlistedPackages = context.getResources() - .getStringArray(com.android.internal.R.array.config_companionDevicePackages); + return isPackageAllowlisted(context, packageManagerInternal, packageName, + config_companionDevicePackages, config_companionDeviceCerts); + } + + /** + * Check if perm sync is allowlisted and auto-enabled for the package. + */ + public static boolean isPermSyncAutoEnabled(Context context, + PackageManagerInternal packageManagerInternal, String packageName) { + return isPackageAllowlisted(context, packageManagerInternal, packageName, + config_companionPermSyncEnabledPackages, config_companionPermSyncEnabledCerts); + } + + private static boolean isPackageAllowlisted(Context context, + PackageManagerInternal packageManagerInternal, String packageName, + int packagesConfig, int certsConfig) { + final String[] allowlistedPackages = context.getResources().getStringArray(packagesConfig); if (!ArrayUtils.contains(allowlistedPackages, packageName)) { Slog.d(TAG, packageName + " is not allowlisted."); return false; } final String[] allowlistedPackagesSignatureDigests = context.getResources() - .getStringArray(com.android.internal.R.array.config_companionDeviceCerts); + .getStringArray(certsConfig); final Set<String> allowlistedSignatureDigestsForRequestingPackage = new HashSet<>(); for (int i = 0; i < allowlistedPackages.length; i++) { if (allowlistedPackages[i].equals(packageName)) { diff --git a/services/core/Android.bp b/services/core/Android.bp index d153c18b54b0..dc1155a484fb 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -232,6 +232,7 @@ java_library_static { "android.hardware.rebootescrow-V1-java", "android.hardware.power.stats-V2-java", "android.hidl.manager-V1.2-java", + "audio-permission-aidl-java", "cbor-java", "com.android.media.audio-aconfig-java", "icu4j_calendar_astronomer", diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java index c7a83693e063..d04dbc2f417e 100644 --- a/services/core/java/com/android/server/PinnerService.java +++ b/services/core/java/com/android/server/PinnerService.java @@ -121,7 +121,6 @@ public final class PinnerService extends SystemService { SystemProperties.getBoolean("pinner.use_pinlist", true); private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); // 80MB max for camera app. - private static final int MAX_HOME_PIN_SIZE = 6 * (1 << 20); // 6MB max for home app. private static final int MAX_ASSISTANT_PIN_SIZE = 60 * (1 << 20); // 60MB max for assistant app. public static final String ANON_REGION_STAT_NAME = "[anon]"; @@ -176,7 +175,7 @@ public final class PinnerService extends SystemService { // Resource-configured pinner flags; private final boolean mConfiguredToPinCamera; - private final boolean mConfiguredToPinHome; + private final int mConfiguredHomePinBytes; private final boolean mConfiguredToPinAssistant; private final int mConfiguredWebviewPinBytes; @@ -238,8 +237,8 @@ public final class PinnerService extends SystemService { mDeviceConfigInterface = mInjector.getDeviceConfigInterface(); mConfiguredToPinCamera = context.getResources().getBoolean( com.android.internal.R.bool.config_pinnerCameraApp); - mConfiguredToPinHome = context.getResources().getBoolean( - com.android.internal.R.bool.config_pinnerHomeApp); + mConfiguredHomePinBytes = context.getResources().getInteger( + com.android.internal.R.integer.config_pinnerHomePinBytes); mConfiguredToPinAssistant = context.getResources().getBoolean( com.android.internal.R.bool.config_pinnerAssistantApp); mConfiguredWebviewPinBytes = context.getResources().getInteger( @@ -390,7 +389,7 @@ public final class PinnerService extends SystemService { @Override public void onChange(boolean selfChange, Uri uri) { if (userSetupCompleteUri.equals(uri)) { - if (mConfiguredToPinHome) { + if (mConfiguredHomePinBytes > 0) { sendPinAppMessage(KEY_HOME, ActivityManager.getCurrentUser(), true /* force */); } @@ -594,7 +593,7 @@ public final class PinnerService extends SystemService { Slog.i(TAG, "Pinner - skip pinning camera app"); } - if (mConfiguredToPinHome) { + if (mConfiguredHomePinBytes > 0) { pinKeys.add(KEY_HOME); } if (mConfiguredToPinAssistant) { @@ -815,7 +814,7 @@ public final class PinnerService extends SystemService { case KEY_CAMERA: return MAX_CAMERA_PIN_SIZE; case KEY_HOME: - return MAX_HOME_PIN_SIZE; + return mConfiguredHomePinBytes; case KEY_ASSISTANT: return MAX_ASSISTANT_PIN_SIZE; default: diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index f1776f4f9148..f1d358486333 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -1986,11 +1986,9 @@ final class UiModeManagerService extends SystemService { // the status bar should be totally disabled, the calls below will // have no effect until the device is unlocked. if (mStatusBarManager != null) { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - if (mCarModeEnabled) { - info.setNotificationTickerDisabled(true); - } - mStatusBarManager.requestDisabledComponent(info, "adjustStatusBarCarModeLocked"); + mStatusBarManager.disable(mCarModeEnabled + ? StatusBarManager.DISABLE_NOTIFICATION_TICKER + : StatusBarManager.DISABLE_NONE); } if (mNotificationManager == null) { diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java index 1015ad9fe1da..ac9ed0da95a5 100644 --- a/services/core/java/com/android/server/accounts/AccountManagerService.java +++ b/services/core/java/com/android/server/accounts/AccountManagerService.java @@ -4532,8 +4532,13 @@ public class AccountManagerService public Account[] getAccountsAsUser(String type, int userId, String opPackageName) { int callingUid = Binder.getCallingUid(); mAppOpsManager.checkPackage(callingUid, opPackageName); - return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1, - opPackageName, false /* includeUserManagedNotVisible */); + try { + return getAccountsAsUserForPackage(type, userId, opPackageName /* callingPackage */, -1, + opPackageName, false /* includeUserManagedNotVisible */); + } catch (SQLiteCantOpenDatabaseException e) { + Log.e(TAG, "Could not get accounts for user " + userId, e); + return new Account[]{}; + } } @NonNull diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 94bf813d3696..9be0e1ff464e 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -3783,6 +3783,14 @@ public final class ActiveServices { return fgsInfo.getLastFgsStartTime() + Math.max(0, timeLimit - fgsInfo.getTotalRuntime()); } + private TimeLimitedFgsInfo getFgsTimeLimitedInfo(int uid, int fgsType) { + final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(uid); + if (fgsInfo != null) { + return fgsInfo.get(fgsType); + } + return null; + } + private void maybeUpdateFgsTrackingLocked(ServiceRecord sr, int previousFgsType) { final int previouslyTimeLimitedType = getTimeLimitedFgsType(previousFgsType); if (previouslyTimeLimitedType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE @@ -3793,16 +3801,12 @@ public final class ActiveServices { if (previouslyTimeLimitedType != ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) { // FGS is switching types and the previous type was time-limited so update the runtime. - final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); - if (fgsInfo != null) { - final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(previouslyTimeLimitedType); - if (fgsTypeInfo != null) { - // Update the total runtime for the previous time-limited fgs type. - fgsTypeInfo.updateTotalRuntime(); - // TODO(b/330399444): handle the case where an app is running 2 services of the - // same time-limited type in parallel and stops one of them which leads to the - // second running one gaining additional runtime. - } + final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo( + sr.appInfo.uid, previouslyTimeLimitedType); + if (fgsTypeInfo != null) { + // Update the total runtime for the previous time-limited fgs type. + fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis()); + fgsTypeInfo.decNumParallelServices(); } if (!sr.isFgsTimeLimited()) { @@ -3825,10 +3829,10 @@ public final class ActiveServices { final int timeLimitedFgsType = getTimeLimitedFgsType(sr.foregroundServiceType); TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedFgsType); if (fgsTypeInfo == null) { - fgsTypeInfo = sr.createTimeLimitedFgsInfo(nowUptime); + fgsTypeInfo = sr.createTimeLimitedFgsInfo(); fgsInfo.put(timeLimitedFgsType, fgsTypeInfo); } - fgsTypeInfo.setLastFgsStartTime(nowUptime); + fgsTypeInfo.noteFgsFgsStart(nowUptime); // We'll cancel the previous ANR timer and start a fresh one below. mFGSAnrTimer.cancel(sr); @@ -3852,13 +3856,12 @@ public final class ActiveServices { return; // if the current fgs type is not time-limited, return. } - final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); - if (fgsInfo != null) { - final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(timeLimitedType); - if (fgsTypeInfo != null) { - // Update the total runtime for the previous time-limited fgs type. - fgsTypeInfo.updateTotalRuntime(); - } + final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo( + sr.appInfo.uid, timeLimitedType); + if (fgsTypeInfo != null) { + // Update the total runtime for the previous time-limited fgs type. + fgsTypeInfo.updateTotalRuntime(SystemClock.uptimeMillis()); + fgsTypeInfo.decNumParallelServices(); } Slog.d(TAG_SERVICE, "Stop FGS timeout: " + sr); mFGSAnrTimer.cancel(sr); @@ -3913,24 +3916,21 @@ public final class ActiveServices { mFGSAnrTimer.accept(sr); traceInstant("FGS timed out: ", sr); - final SparseArray<TimeLimitedFgsInfo> fgsInfo = mTimeLimitedFgsInfo.get(sr.appInfo.uid); - if (fgsInfo != null) { - final TimeLimitedFgsInfo fgsTypeInfo = fgsInfo.get(fgsType); - if (fgsTypeInfo != null) { - // Update total runtime for the time-limited fgs type and mark it as timed out. - fgsTypeInfo.updateTotalRuntime(); - fgsTypeInfo.setTimeLimitExceededAt(nowUptime); - - logFGSStateChangeLocked(sr, - FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT, - nowUptime > fgsTypeInfo.getLastFgsStartTime() - ? (int) (nowUptime - fgsTypeInfo.getLastFgsStartTime()) : 0, - FGS_STOP_REASON_UNKNOWN, - FGS_TYPE_POLICY_CHECK_UNKNOWN, - FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, - false /* fgsRestrictionRecalculated */ - ); - } + final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(sr.appInfo.uid, fgsType); + if (fgsTypeInfo != null) { + // Update total runtime for the time-limited fgs type and mark it as timed out. + fgsTypeInfo.updateTotalRuntime(nowUptime); + fgsTypeInfo.setTimeLimitExceededAt(nowUptime); + + logFGSStateChangeLocked(sr, + FOREGROUND_SERVICE_STATE_CHANGED__STATE__TIMED_OUT, + nowUptime > fgsTypeInfo.getFirstFgsStartUptime() + ? (int) (nowUptime - fgsTypeInfo.getFirstFgsStartUptime()) : 0, + FGS_STOP_REASON_UNKNOWN, + FGS_TYPE_POLICY_CHECK_UNKNOWN, + FOREGROUND_SERVICE_STATE_CHANGED__FGS_START_API__FGSSTARTAPI_NA, + false /* fgsRestrictionRecalculated */ + ); } try { @@ -3949,6 +3949,16 @@ public final class ActiveServices { if (fgsType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) { return; // no timed out FGS type was found (either it was stopped or it switched types) } + + synchronized (mAm) { + final TimeLimitedFgsInfo fgsTypeInfo = getFgsTimeLimitedInfo(sr.appInfo.uid, fgsType); + if (fgsTypeInfo != null) { + // Runtime is already updated when the service times out - if the app didn't + // stop the service, decrement the number of parallel running services here. + fgsTypeInfo.decNumParallelServices(); + } + } + final String reason = "A foreground service of type " + ServiceInfo.foregroundServiceTypeToLabel(fgsType) + " did not stop within its timeout: " + sr.getComponentName(); @@ -3958,7 +3968,6 @@ public final class ActiveServices { Slog.wtf(TAG, reason); return; } - if (android.app.Flags.enableFgsTimeoutCrashBehavior()) { // Crash the app synchronized (mAm) { @@ -4005,7 +4014,6 @@ public final class ActiveServices { private void stopServiceAndUpdateAllowlistManagerLocked(ServiceRecord service) { maybeStopShortFgsTimeoutLocked(service); - maybeStopFgsTimeoutLocked(service); final ProcessServiceRecord psr = service.app.mServices; psr.stopService(service); psr.updateBoundClientUids(); @@ -6291,7 +6299,6 @@ public final class ActiveServices { Slog.w(TAG_SERVICE, "Short FGS brought down without stopping: " + r); maybeStopShortFgsTimeoutLocked(r); } - maybeStopFgsTimeoutLocked(r); // Report to all of the connections that the service is no longer // available. @@ -6416,7 +6423,6 @@ public final class ActiveServices { final boolean exitingFg = r.isForeground; if (exitingFg) { maybeStopShortFgsTimeoutLocked(r); - maybeStopFgsTimeoutLocked(r); decActiveForegroundAppLocked(smap, r); synchronized (mAm.mProcessStats.mLock) { ServiceState stracker = r.getTracker(); diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java index f2b9b25d6097..31704c442290 100644 --- a/services/core/java/com/android/server/am/ConnectionRecord.java +++ b/services/core/java/com/android/server/am/ConnectionRecord.java @@ -136,6 +136,13 @@ final class ConnectionRecord implements OomAdjusterModernImpl.Connection{ false, oomAdjReason, UNKNOWN_ADJ, false, false); } + @Override + public boolean canAffectCapabilities() { + return hasFlag(Context.BIND_INCLUDE_CAPABILITIES + | Context.BIND_BYPASS_USER_NETWORK_RESTRICTIONS); + } + + public long getFlags() { return flags; } diff --git a/services/core/java/com/android/server/am/ContentProviderConnection.java b/services/core/java/com/android/server/am/ContentProviderConnection.java index 3988277ab525..ae5ae0133e1b 100644 --- a/services/core/java/com/android/server/am/ContentProviderConnection.java +++ b/services/core/java/com/android/server/am/ContentProviderConnection.java @@ -82,6 +82,12 @@ public final class ContentProviderConnection extends Binder implements false, oomAdjReason, UNKNOWN_ADJ, false, false); } + @Override + public boolean canAffectCapabilities() { + return false; + } + + public void startAssociationIfNeeded() { // If we don't already have an active association, create one... but only if this // is an association between two different processes. diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java index 3268b661df65..9600317faca1 100644 --- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java +++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java @@ -16,6 +16,7 @@ package com.android.server.am; +import static android.app.ActivityManager.PROCESS_CAPABILITY_BFSL; import static android.app.ActivityManager.PROCESS_STATE_BACKUP; import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP; @@ -521,6 +522,11 @@ public class OomAdjusterModernImpl extends OomAdjuster { */ void computeHostOomAdjLSP(OomAdjuster oomAdjuster, ProcessRecord host, ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll, int oomAdjReason, int cachedAdj); + + /** + * Returns true if this connection can propagate capabilities. + */ + boolean canAffectCapabilities(); } /** @@ -553,16 +559,29 @@ public class OomAdjusterModernImpl extends OomAdjuster { */ private class ComputeConnectionIgnoringReachableClientsConsumer implements BiConsumer<Connection, ProcessRecord> { - public OomAdjusterArgs args = null; + private OomAdjusterArgs mArgs = null; + public boolean hasReachableClient = false; + + public void init(OomAdjusterArgs args) { + mArgs = args; + hasReachableClient = false; + } @Override public void accept(Connection conn, ProcessRecord client) { - final ProcessRecord host = args.mApp; - final ProcessRecord topApp = args.mTopApp; - final long now = args.mNow; - final @OomAdjReason int oomAdjReason = args.mOomAdjReason; + final ProcessRecord host = mArgs.mApp; + final ProcessRecord topApp = mArgs.mTopApp; + final long now = mArgs.mNow; + final @OomAdjReason int oomAdjReason = mArgs.mOomAdjReason; + + if (client.mState.isReachable()) { + hasReachableClient = true; + return; + } - if (client.mState.isReachable()) return; + if (unimportantConnectionLSP(conn, host, client)) { + return; + } conn.computeHostOomAdjLSP(OomAdjusterModernImpl.this, host, client, now, topApp, false, oomAdjReason, UNKNOWN_ADJ); @@ -591,6 +610,10 @@ public class OomAdjusterModernImpl extends OomAdjuster { final int prevProcState = host.mState.getCurProcState(); final int prevAdj = host.mState.getCurRawAdj(); + if (unimportantConnectionLSP(conn, host, client)) { + return; + } + conn.computeHostOomAdjLSP(OomAdjusterModernImpl.this, host, client, now, topApp, fullUpdate, oomAdjReason, cachedAdj); @@ -874,7 +897,7 @@ public class OomAdjusterModernImpl extends OomAdjuster { // processes cannot change as a part of this update, their current values can be used // right now. mProcessRecordProcStateNodes.resetLastNodes(); - initReachableStatesLSP(reachables, mTmpOomAdjusterArgs); + initReachableStatesLSP(reachables, targets.size(), mTmpOomAdjusterArgs); // Set adj last nodes now, this way a process will only be reevaluated during the adj node // iteration if they adj score changed during the procState node iteration. @@ -914,8 +937,6 @@ public class OomAdjusterModernImpl extends OomAdjuster { /** * Mark all processes reachable from the {@code reachables} processes and add them to the * provided {@code reachables} list (targets excluded). - * - * Returns true if a cycle exists within the reachable process graph. */ @GuardedBy({"mService", "mProcLock"}) private void collectAndMarkReachableProcessesLSP(ArrayList<ProcessRecord> reachables) { @@ -930,8 +951,35 @@ public class OomAdjusterModernImpl extends OomAdjuster { * Calculate initial importance states for {@code reachables} and update their slot position * if necessary. */ - private void initReachableStatesLSP(ArrayList<ProcessRecord> reachables, OomAdjusterArgs args) { - for (int i = 0, size = reachables.size(); i < size; i++) { + private void initReachableStatesLSP(ArrayList<ProcessRecord> reachables, int targetCount, + OomAdjusterArgs args) { + int i = 0; + boolean initReachables = !Flags.skipUnimportantConnections(); + for (; i < targetCount && !initReachables; i++) { + final ProcessRecord target = reachables.get(i); + final int prevProcState = target.mState.getCurProcState(); + final int prevAdj = target.mState.getCurRawAdj(); + final int prevCapability = target.mState.getCurCapability(); + final boolean prevShouldNotFreeze = target.mOptRecord.shouldNotFreeze(); + + args.mApp = target; + // If target client is a reachable, reachables need to be reinited in case this + // client is important enough to change this target in the computeConnection step. + initReachables |= computeOomAdjIgnoringReachablesLSP(args); + // If target lowered in importance, reachables need to be reinited because this + // target may have been the source of a reachable's current importance. + initReachables |= selfImportanceLoweredLSP(target, prevProcState, prevAdj, + prevCapability, prevShouldNotFreeze); + + updateProcStateSlot(target, prevProcState); + updateAdjSlot(target, prevAdj); + } + + if (!initReachables) { + return; + } + + for (int size = reachables.size(); i < size; i++) { final ProcessRecord reachable = reachables.get(i); final int prevProcState = reachable.mState.getCurProcState(); final int prevAdj = reachable.mState.getCurRawAdj(); @@ -948,9 +996,11 @@ public class OomAdjusterModernImpl extends OomAdjuster { * Calculate initial importance states for {@code app}. * Processes not marked reachable cannot change as a part of this update, so connections from * those process can be calculated now. + * + * Returns true if any client connection was skipped due to a reachablity cycle. */ @GuardedBy({"mService", "mProcLock"}) - private void computeOomAdjIgnoringReachablesLSP(OomAdjusterArgs args) { + private boolean computeOomAdjIgnoringReachablesLSP(OomAdjusterArgs args) { final ProcessRecord app = args.mApp; final ProcessRecord topApp = args.mTopApp; final long now = args.mNow; @@ -958,8 +1008,9 @@ public class OomAdjusterModernImpl extends OomAdjuster { computeOomAdjLSP(app, UNKNOWN_ADJ, topApp, false, now, false, false, oomAdjReason, false); - mComputeConnectionIgnoringReachableClientsConsumer.args = args; + mComputeConnectionIgnoringReachableClientsConsumer.init(args); forEachClientConnectionLSP(app, mComputeConnectionIgnoringReachableClientsConsumer); + return mComputeConnectionIgnoringReachableClientsConsumer.hasReachableClient; } /** @@ -1039,6 +1090,7 @@ public class OomAdjusterModernImpl extends OomAdjuster { } else { client = cr.binding.client; } + if (client == null || client == app) continue; connectionConsumer.accept(cr, client); } } @@ -1053,4 +1105,66 @@ public class OomAdjusterModernImpl extends OomAdjuster { } } } + + /** + * Returns true if at least one the provided values is more important than those in {@code app}. + */ + @GuardedBy({"mService", "mProcLock"}) + private static boolean selfImportanceLoweredLSP(ProcessRecord app, int prevProcState, + int prevAdj, int prevCapability, boolean prevShouldNotFreeze) { + if (app.mState.getCurProcState() > prevProcState) { + return true; + } + if (app.mState.getCurRawAdj() > prevAdj) { + return true; + } + if ((app.mState.getCurCapability() & prevCapability) != prevCapability) { + return true; + } + if (!app.mOptRecord.shouldNotFreeze() && prevShouldNotFreeze) { + // No long marked as should not freeze. + return true; + } + return false; + } + + /** + * Returns whether a host connection evaluation can be skipped due to lack of importance. + * Note: the client and host need to be provided as well for the isolated and sandbox + * scenarios. + */ + @GuardedBy({"mService", "mProcLock"}) + private static boolean unimportantConnectionLSP(Connection conn, + ProcessRecord host, ProcessRecord client) { + if (!Flags.skipUnimportantConnections()) { + // Feature not enabled, just return false so the connection is evaluated. + return false; + } + if (host.mState.getCurProcState() > client.mState.getCurProcState()) { + return false; + } + if (host.mState.getCurRawAdj() > client.mState.getCurRawAdj()) { + return false; + } + final int serviceCapability = host.mState.getCurCapability(); + final int clientCapability = client.mState.getCurCapability(); + if ((serviceCapability & clientCapability) != clientCapability) { + // Client has a capability the host does not have. + if ((clientCapability & PROCESS_CAPABILITY_BFSL) == PROCESS_CAPABILITY_BFSL + && (serviceCapability & PROCESS_CAPABILITY_BFSL) == 0) { + // The BFSL capability does not need a flag to propagate. + return false; + } + if (conn.canAffectCapabilities()) { + // One of these bind flags may propagate that capability. + return false; + } + } + + if (!host.mOptRecord.shouldNotFreeze() && client.mOptRecord.shouldNotFreeze()) { + // If the client is marked as should not freeze, so should the host. + return false; + } + return true; + } } diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 8eca4fc0d2ff..218434049869 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -690,10 +690,14 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN private long mTimeLimitExceededAt = Long.MIN_VALUE; @UptimeMillisLong private long mTotalRuntime = 0; + private int mNumParallelServices = 0; - TimeLimitedFgsInfo(@UptimeMillisLong long startTime) { - mFirstFgsStartUptime = startTime; - mFirstFgsStartRealtime = SystemClock.elapsedRealtime(); + public void noteFgsFgsStart(@UptimeMillisLong long startTime) { + mNumParallelServices++; + if (mNumParallelServices == 1) { + mFirstFgsStartUptime = startTime; + mFirstFgsStartRealtime = SystemClock.elapsedRealtime(); + } mLastFgsStartTime = startTime; } @@ -707,17 +711,23 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN return mFirstFgsStartRealtime; } - public void setLastFgsStartTime(@UptimeMillisLong long startTime) { - mLastFgsStartTime = startTime; - } - @UptimeMillisLong public long getLastFgsStartTime() { return mLastFgsStartTime; } - public void updateTotalRuntime() { - mTotalRuntime += SystemClock.uptimeMillis() - mLastFgsStartTime; + public void decNumParallelServices() { + if (mNumParallelServices > 0) { + mNumParallelServices--; + } + if (mNumParallelServices == 0) { + mLastFgsStartTime = 0; + } + } + + public void updateTotalRuntime(@UptimeMillisLong long nowUptime) { + mTotalRuntime += nowUptime - mLastFgsStartTime; + mLastFgsStartTime = nowUptime; } @UptimeMillisLong @@ -735,6 +745,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN } public void reset() { + mNumParallelServices = 0; mFirstFgsStartUptime = 0; mFirstFgsStartRealtime = 0; mLastFgsStartTime = 0; @@ -1872,8 +1883,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN /** * Called when a time-limited FGS starts. */ - public TimeLimitedFgsInfo createTimeLimitedFgsInfo(@UptimeMillisLong long nowUptime) { - return new TimeLimitedFgsInfo(nowUptime); + public TimeLimitedFgsInfo createTimeLimitedFgsInfo() { + return new TimeLimitedFgsInfo(); } /** diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig index fb63ec619918..b7108dfcbac3 100644 --- a/services/core/java/com/android/server/am/flags.aconfig +++ b/services/core/java/com/android/server/am/flags.aconfig @@ -116,3 +116,10 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "skip_unimportant_connections" + namespace: "backstage_power" + description: "Avoid OomAdjuster calculations for connections that won't change importance" + bug: "323376416" +} diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 1db3483e3800..ad93f6fc8d9f 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -55,6 +55,7 @@ import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED; import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM; import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM_OPS; import static android.app.AppOpsManager.SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE; +import static android.app.AppOpsManager.UID_STATE_NONEXISTENT; import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES; import static android.app.AppOpsManager._NUM_OP; import static android.app.AppOpsManager.extractFlagsFromKey; @@ -70,7 +71,6 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.Intent.EXTRA_REPLACING; import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP; -import static android.permission.flags.Flags.runtimePermissionAppopsMappingEnabled; import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS; @@ -130,6 +130,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.storage.StorageManagerInternal; import android.permission.PermissionManager; +import android.permission.flags.Flags; import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; @@ -140,6 +141,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; +import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.Xml; @@ -153,7 +155,6 @@ import com.android.internal.app.IAppOpsNotedCallback; import com.android.internal.app.IAppOpsService; import com.android.internal.app.IAppOpsStartedCallback; import com.android.internal.app.MessageSamplingConfig; -import com.android.internal.camera.flags.Flags; import com.android.internal.compat.IPlatformCompat; import com.android.internal.os.Clock; import com.android.internal.pm.pkg.component.ParsedAttribution; @@ -1421,6 +1422,9 @@ public class AppOpsService extends IAppOpsService.Stub { // The callback method from AppOpsUidStateTracker private void onUidStateChanged(int uid, int state, boolean foregroundModeMayChange) { synchronized (this) { + if (state == UID_STATE_NONEXISTENT) { + onUidProcessDeathLocked(uid); + } UidState uidState = getUidStateLocked(uid, false); boolean hasForegroundWatchers = false; @@ -1508,6 +1512,11 @@ public class AppOpsService extends IAppOpsService.Stub { } } + if (state == UID_STATE_NONEXISTENT) { + // For UID_STATE_NONEXISTENT, we don't call onUidStateChanged for AttributedOps + return; + } + if (uidState != null) { int numPkgs = uidState.pkgOps.size(); for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) { @@ -1532,6 +1541,81 @@ public class AppOpsService extends IAppOpsService.Stub { } } + @GuardedBy("this") + private void onUidProcessDeathLocked(int uid) { + if (!mUidStates.contains(uid) || !Flags.finishRunningOpsForKilledPackages()) { + return; + } + final SparseLongArray chainsToFinish = new SparseLongArray(); + doForAllAttributedOpsInUidLocked(uid, (attributedOp) -> { + attributedOp.doForAllInProgressStartOpEvents((event) -> { + int chainId = event.getAttributionChainId(); + if (chainId != ATTRIBUTION_CHAIN_ID_NONE) { + long currentEarliestStartTime = + chainsToFinish.get(chainId, Long.MAX_VALUE); + if (event.getStartTime() < currentEarliestStartTime) { + // Store the earliest chain link we're finishing, so that we can go back + // and finish any links in the chain that started after this one + chainsToFinish.put(chainId, event.getStartTime()); + } + } + attributedOp.finished(event.getClientId()); + }); + }); + finishChainsLocked(chainsToFinish); + } + + @GuardedBy("this") + private void finishChainsLocked(SparseLongArray chainsToFinish) { + doForAllAttributedOpsLocked((attributedOp) -> { + attributedOp.doForAllInProgressStartOpEvents((event) -> { + int chainId = event.getAttributionChainId(); + // If this event is part of a chain, and this event started after the event in the + // chain we already finished, then finish this event, too + long earliestEventStart = chainsToFinish.get(chainId, Long.MAX_VALUE); + if (chainId != ATTRIBUTION_CHAIN_ID_NONE + && event.getStartTime() >= earliestEventStart) { + attributedOp.finished(event.getClientId()); + } + }); + }); + } + + @GuardedBy("this") + private void doForAllAttributedOpsLocked(Consumer<AttributedOp> action) { + int numUids = mUidStates.size(); + for (int uidNum = 0; uidNum < numUids; uidNum++) { + int uid = mUidStates.keyAt(uidNum); + doForAllAttributedOpsInUidLocked(uid, action); + } + } + + @GuardedBy("this") + private void doForAllAttributedOpsInUidLocked(int uid, Consumer<AttributedOp> action) { + UidState uidState = mUidStates.get(uid); + if (uidState == null) { + return; + } + + int numPkgs = uidState.pkgOps.size(); + for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) { + Ops ops = uidState.pkgOps.valueAt(pkgNum); + int numOps = ops.size(); + for (int opNum = 0; opNum < numOps; opNum++) { + Op op = ops.valueAt(opNum); + int numDevices = op.mDeviceAttributedOps.size(); + for (int deviceNum = 0; deviceNum < numDevices; deviceNum++) { + ArrayMap<String, AttributedOp> attrOps = + op.mDeviceAttributedOps.valueAt(deviceNum); + int numAttributions = attrOps.size(); + for (int attrNum = 0; attrNum < numAttributions; attrNum++) { + action.accept(attrOps.valueAt(attrNum)); + } + } + } + } + } + /** * Notify the proc state or capability has changed for a certain UID. */ @@ -2702,7 +2786,7 @@ public class AppOpsService extends IAppOpsService.Stub { * have information on them. */ private static boolean isOpAllowedForUid(int uid) { - return runtimePermissionAppopsMappingEnabled() + return Flags.runtimePermissionAppopsMappingEnabled() && (uid == Process.ROOT_UID || uid == Process.SYSTEM_UID); } @@ -4775,8 +4859,8 @@ public class AppOpsService extends IAppOpsService.Stub { if ((code == OP_CAMERA) && isAutomotive()) { final long identity = Binder.clearCallingIdentity(); try { - if ((Flags.cameraPrivacyAllowlist()) - && (mSensorPrivacyManager.isCameraPrivacyEnabled(packageName))) { + if (com.android.internal.camera.flags.Flags.cameraPrivacyAllowlist() + && mSensorPrivacyManager.isCameraPrivacyEnabled(packageName)) { return true; } } finally { diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java b/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java index 18ea8cfc1386..268b286d8fe1 100644 --- a/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java +++ b/services/core/java/com/android/server/appop/AppOpsUidStateTracker.java @@ -68,6 +68,7 @@ interface AppOpsUidStateTracker { return UID_STATE_BACKGROUND; } + // UID_STATE_NONEXISTENT is deliberately excluded here return UID_STATE_CACHED; } diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java index bc6ef2005584..03c81560be89 100644 --- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java +++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java @@ -34,7 +34,9 @@ import static android.app.AppOpsManager.OP_RECORD_AUDIO; import static android.app.AppOpsManager.OP_TAKE_AUDIO_FOCUS; import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE; import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED; +import static android.app.AppOpsManager.UID_STATE_NONEXISTENT; import static android.app.AppOpsManager.UID_STATE_TOP; +import static android.permission.flags.Flags.finishRunningOpsForKilledPackages; import static com.android.server.appop.AppOpsUidStateTracker.processStateToUidState; @@ -343,13 +345,14 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE); boolean appWidgetVisible = mAppWidgetVisible.get(uid, false); + boolean foregroundChange = uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED + != pendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED + || capability != pendingCapability + || appWidgetVisible != pendingAppWidgetVisible; + if (uidState != pendingUidState || capability != pendingCapability || appWidgetVisible != pendingAppWidgetVisible) { - boolean foregroundChange = uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED - != pendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED - || capability != pendingCapability - || appWidgetVisible != pendingAppWidgetVisible; if (foregroundChange) { // To save on memory usage, log only interesting changes. @@ -372,6 +375,16 @@ class AppOpsUidStateTrackerImpl implements AppOpsUidStateTracker { mCapability.delete(uid); mAppWidgetVisible.delete(uid); mPendingGone.delete(uid); + if (finishRunningOpsForKilledPackages()) { + for (int i = 0; i < mUidStateChangedCallbacks.size(); i++) { + UidStateChangedCallback cb = mUidStateChangedCallbacks.keyAt(i); + Executor executor = mUidStateChangedCallbacks.valueAt(i); + + executor.execute(PooledLambda.obtainRunnable( + UidStateChangedCallback::onUidStateChanged, cb, uid, + UID_STATE_NONEXISTENT, foregroundChange)); + } + } } else { mUidStates.put(uid, pendingUidState); mCapability.put(uid, pendingCapability); diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java index 2760ccf72f98..02fc9938c02c 100644 --- a/services/core/java/com/android/server/appop/AttributedOp.java +++ b/services/core/java/com/android/server/appop/AttributedOp.java @@ -38,6 +38,7 @@ import com.android.internal.util.function.pooled.PooledLambda; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; +import java.util.function.Consumer; final class AttributedOp { private final @NonNull AppOpsService mAppOpsService; @@ -256,6 +257,19 @@ final class AttributedOp { } } + public void doForAllInProgressStartOpEvents(Consumer<InProgressStartOpEvent> action) { + ArrayMap<IBinder, AttributedOp.InProgressStartOpEvent> events = isPaused() + ? mPausedInProgressEvents : mInProgressEvents; + if (events == null) { + return; + } + + int numStartedOps = events.size(); + for (int i = 0; i < numStartedOps; i++) { + action.accept(events.valueAt(i)); + } + } + /** * Update state when finishOp was called. Will finish started ops, and delete paused ops. * diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index add84910bf48..15c5c1077803 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -4440,7 +4440,8 @@ public class AudioService extends IAudioService.Stub || usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING) { voiceActive = true; } - if (usage == AudioAttributes.USAGE_MEDIA || usage == AudioAttributes.USAGE_GAME) { + if (usage == AudioAttributes.USAGE_MEDIA || usage == AudioAttributes.USAGE_GAME + || usage == AudioAttributes.USAGE_UNKNOWN) { mediaActive = true; } } @@ -9778,9 +9779,9 @@ public class AudioService extends IAudioService.Stub mContentResolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this); mContentResolver.registerContentObserver(Settings.System.getUriFor( - Settings.System.MASTER_MONO), false, this); + Settings.System.MASTER_MONO), false, this, UserHandle.USER_ALL); mContentResolver.registerContentObserver(Settings.System.getUriFor( - Settings.System.MASTER_BALANCE), false, this); + Settings.System.MASTER_BALANCE), false, this, UserHandle.USER_ALL); mEncodedSurroundMode = mSettings.getGlobalInt( mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT, diff --git a/services/core/java/com/android/server/audio/MusicFxHelper.java b/services/core/java/com/android/server/audio/MusicFxHelper.java index ba453101046f..cf0b2ae15618 100644 --- a/services/core/java/com/android/server/audio/MusicFxHelper.java +++ b/services/core/java/com/android/server/audio/MusicFxHelper.java @@ -70,6 +70,8 @@ public class MusicFxHelper { // The binder token identifying the UidObserver registration. private IBinder mUidObserverToken = null; + private boolean mIsBound; + // Package name and list of open audio sessions for this package private static class PackageSessions { String mPackageName; @@ -109,6 +111,7 @@ public class MusicFxHelper { if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { Intent bindIntent = new Intent().setClassName(mMusicFxPackageName, "com.android.musicfx.KeepAliveService"); + mIsBound = true; mContext.bindServiceAsUser( bindIntent, mMusicFxBindConnection, Context.BIND_AUTO_CREATE, UserHandle.of(getCurrentUserId())); @@ -157,9 +160,12 @@ public class MusicFxHelper { Log.e(TAG, "RemoteException with unregisterUidObserver: " + e); } mUidObserverToken = null; - mContext.unbindService(mMusicFxBindConnection); - Log.i(TAG, "last session closed, unregister UID observer, and unbind " - + mMusicFxPackageName); + if (mIsBound) { + mContext.unbindService(mMusicFxBindConnection); + mIsBound = false; + Log.i(TAG, "last session closed, unregister UID observer, and unbind " + + mMusicFxPackageName); + } } } } diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java index e2c4b4638207..cae169550d9a 100644 --- a/services/core/java/com/android/server/audio/SpatializerHelper.java +++ b/services/core/java/com/android/server/audio/SpatializerHelper.java @@ -347,9 +347,6 @@ public class SpatializerHelper { //------------------------------------------------------ // routing monitoring synchronized void onRoutingUpdated() { - if (!mFeatureEnabled) { - return; - } switch (mState) { case STATE_UNINITIALIZED: case STATE_NOT_SUPPORTED: @@ -393,7 +390,7 @@ public class SpatializerHelper { setDispatchAvailableState(false); } - boolean enabled = able && enabledAvailable.first; + boolean enabled = mFeatureEnabled && able && enabledAvailable.first; if (enabled) { loglogi("Enabling Spatial Audio since enabled for media device:" + currentDevice); diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java index 11cca66318d6..2a1687209aad 100644 --- a/services/core/java/com/android/server/biometrics/AuthService.java +++ b/services/core/java/com/android/server/biometrics/AuthService.java @@ -298,7 +298,7 @@ public class AuthService extends SystemService { return -1; } - if (promptInfo.containsTestConfigurations()) { + if (promptInfo.requiresTestOrInternalPermission()) { if (getContext().checkCallingOrSelfPermission(TEST_BIOMETRIC) != PackageManager.PERMISSION_GRANTED) { checkInternalPermission(); @@ -306,10 +306,10 @@ public class AuthService extends SystemService { } // Only allow internal clients to enable non-public options. - if (promptInfo.containsPrivateApiConfigurations()) { + if (promptInfo.requiresInternalPermission()) { checkInternalPermission(); } - if (promptInfo.containsAdvancedApiConfigurations()) { + if (promptInfo.requiresAdvancedPermission()) { checkBiometricAdvancedPermission(); } diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index d9c3ab806888..30d12e670a6c 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -1189,7 +1189,11 @@ public class AutomaticBrightnessController { update(); } - void switchMode(@AutomaticBrightnessMode int mode) { + /** + * Responsible for switching the AutomaticBrightnessMode of the associated display. Also takes + * care of resetting the short term model wherever required + */ + public void switchMode(@AutomaticBrightnessMode int mode) { if (!mBrightnessMappingStrategyMap.contains(mode)) { return; } diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index 70a1014a0c8c..875fd059d612 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -84,6 +84,7 @@ import com.android.server.display.brightness.BrightnessUtils; import com.android.server.display.brightness.DisplayBrightnessController; import com.android.server.display.brightness.clamper.BrightnessClamperController; import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy2; +import com.android.server.display.brightness.strategy.DisplayBrightnessStrategyConstants; import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal; import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener; import com.android.server.display.config.HysteresisLevels; @@ -1333,12 +1334,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call mDisplayStateController.shouldPerformScreenOffTransition()); state = mPowerState.getScreenState(); - // Switch to doze auto-brightness mode if needed - if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null - && !mAutomaticBrightnessController.isInIdleMode()) { - mAutomaticBrightnessController.switchMode(Display.isDozeState(state) - ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT); - } DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController .updateBrightness(mPowerRequest, state); @@ -1372,6 +1367,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call final boolean wasShortTermModelActive = mAutomaticBrightnessStrategy.isShortTermModelActive(); if (!mFlags.isRefactorDisplayPowerControllerEnabled()) { + // Switch to doze auto-brightness mode if needed + if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null + && !mAutomaticBrightnessController.isInIdleMode()) { + mAutomaticBrightnessController.switchMode(Display.isDozeState(state) + ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT); + } + mAutomaticBrightnessStrategy.setAutoBrightnessState(state, mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(), mBrightnessReasonTemp.getReason(), mPowerRequest.policy, @@ -1440,45 +1442,52 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call brightnessState = clampScreenBrightness(brightnessState); } - // If there's an offload session, we need to set the initial doze brightness before - // the offload session starts controlling the brightness. - // During the transition DOZE_SUSPEND -> DOZE -> DOZE_SUSPEND, this brightness strategy - // will be selected again, meaning that no new brightness will be sent to the hardware and - // the display will stay at the brightness level set by the offload session. - if (Float.isNaN(brightnessState) && mFlags.isDisplayOffloadEnabled() - && Display.isDozeState(state) && mDisplayOffloadSession != null) { - if (mAutomaticBrightnessController != null - && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) { - // Use the auto-brightness curve and the last observed lux - rawBrightnessState = mAutomaticBrightnessController - .getAutomaticScreenBrightnessBasedOnLastUsedLux( - mTempBrightnessEvent); - } else { - rawBrightnessState = getDozeBrightnessForOffload(); - mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags() - | BrightnessEvent.FLAG_DOZE_SCALE); - } - - if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) { - brightnessState = clampScreenBrightness(rawBrightnessState); - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL); - + if (Display.isDozeState(state)) { + // If there's an offload session, we need to set the initial doze brightness before + // the offload session starts controlling the brightness. + // During the transition DOZE_SUSPEND -> DOZE -> DOZE_SUSPEND, this brightness strategy + // will be selected again, meaning that no new brightness will be sent to the hardware + // and the display will stay at the brightness level set by the offload session. + if ((Float.isNaN(brightnessState) + || displayBrightnessState.getDisplayBrightnessStrategyName() + .equals(DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME)) + && mFlags.isDisplayOffloadEnabled() + && mDisplayOffloadSession != null) { if (mAutomaticBrightnessController != null && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) { - // Keep the brightness in the setting so that we can use it after the screen - // turns on, until a lux sample becomes available. We don't do this when - // auto-brightness is disabled - in that situation we still want to use - // the last brightness from when the screen was on. - updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState; + // Use the auto-brightness curve and the last observed lux + rawBrightnessState = mAutomaticBrightnessController + .getAutomaticScreenBrightnessBasedOnLastUsedLux( + mTempBrightnessEvent); + } else { + rawBrightnessState = getDozeBrightnessForOffload(); + mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags() + | BrightnessEvent.FLAG_DOZE_SCALE); + } + + if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) { + brightnessState = clampScreenBrightness(rawBrightnessState); + mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL); + + if (mAutomaticBrightnessController != null + && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) { + // Keep the brightness in the setting so that we can use it after the screen + // turns on, until a lux sample becomes available. We don't do this when + // auto-brightness is disabled - in that situation we still want to use + // the last brightness from when the screen was on. + updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState; + } } } - } - // Use default brightness when dozing unless overridden. - if (Float.isNaN(brightnessState) && Display.isDozeState(state)) { - rawBrightnessState = mScreenBrightnessDozeConfig; - brightnessState = clampScreenBrightness(rawBrightnessState); - mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT); + // Use default brightness when dozing unless overridden. + if (Float.isNaN(brightnessState) + || displayBrightnessState.getDisplayBrightnessStrategyName() + .equals(DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME)) { + rawBrightnessState = mScreenBrightnessDozeConfig; + brightnessState = clampScreenBrightness(rawBrightnessState); + mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT); + } } if (!mFlags.isRefactorDisplayPowerControllerEnabled()) { @@ -1502,7 +1511,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } // Apply manual brightness. - if (Float.isNaN(brightnessState)) { + if (Float.isNaN(brightnessState) && !mFlags.isRefactorDisplayPowerControllerEnabled()) { rawBrightnessState = currentBrightnessSetting; brightnessState = clampScreenBrightness(rawBrightnessState); if (brightnessState != currentBrightnessSetting) { diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java index 22a21a6c113c..feec4e6b2259 100644 --- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java +++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java @@ -32,6 +32,7 @@ import com.android.server.display.brightness.strategy.AutomaticBrightnessStrateg import com.android.server.display.brightness.strategy.BoostBrightnessStrategy; import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy; import com.android.server.display.brightness.strategy.DozeBrightnessStrategy; +import com.android.server.display.brightness.strategy.FallbackBrightnessStrategy; import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy; import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy; import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy; @@ -85,6 +86,9 @@ public class DisplayBrightnessStrategySelector { @Nullable private final AutoBrightnessFallbackStrategy mAutoBrightnessFallbackStrategy; + @Nullable + private final FallbackBrightnessStrategy mFallbackBrightnessStrategy; + // A collective representation of all the strategies that the selector is aware of. This is // non null, but the strategies this is tracking can be null @NonNull @@ -118,7 +122,8 @@ public class DisplayBrightnessStrategySelector { mInvalidBrightnessStrategy = injector.getInvalidBrightnessStrategy(); mAutomaticBrightnessStrategy1 = (!mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) ? null - : injector.getAutomaticBrightnessStrategy1(context, displayId); + : injector.getAutomaticBrightnessStrategy1(context, displayId, + mDisplayManagerFlags); mAutomaticBrightnessStrategy2 = (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) ? null : injector.getAutomaticBrightnessStrategy2(context, displayId); @@ -134,11 +139,14 @@ public class DisplayBrightnessStrategySelector { } else { mOffloadBrightnessStrategy = null; } + mFallbackBrightnessStrategy = (mDisplayManagerFlags + .isRefactorDisplayPowerControllerEnabled()) + ? injector.getFallbackBrightnessStrategy() : null; mDisplayBrightnessStrategies = new DisplayBrightnessStrategy[]{mInvalidBrightnessStrategy, mScreenOffBrightnessStrategy, mDozeBrightnessStrategy, mFollowerBrightnessStrategy, mBoostBrightnessStrategy, mOverrideBrightnessStrategy, mTemporaryBrightnessStrategy, mAutomaticBrightnessStrategy1, mOffloadBrightnessStrategy, - mAutoBrightnessFallbackStrategy}; + mAutoBrightnessFallbackStrategy, mFallbackBrightnessStrategy}; mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean( R.bool.config_allowAutoBrightnessWhileDozing); mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName(); @@ -179,6 +187,12 @@ public class DisplayBrightnessStrategySelector { displayBrightnessStrategy = mOffloadBrightnessStrategy; } else if (isAutoBrightnessFallbackStrategyValid()) { displayBrightnessStrategy = mAutoBrightnessFallbackStrategy; + } else { + // This will become the ultimate fallback strategy once the flag has been fully rolled + // out + if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) { + displayBrightnessStrategy = mFallbackBrightnessStrategy; + } } if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) { @@ -330,8 +344,8 @@ public class DisplayBrightnessStrategySelector { } AutomaticBrightnessStrategy getAutomaticBrightnessStrategy1(Context context, - int displayId) { - return new AutomaticBrightnessStrategy(context, displayId); + int displayId, DisplayManagerFlags displayManagerFlags) { + return new AutomaticBrightnessStrategy(context, displayId, displayManagerFlags); } AutomaticBrightnessStrategy2 getAutomaticBrightnessStrategy2(Context context, @@ -347,5 +361,9 @@ public class DisplayBrightnessStrategySelector { AutoBrightnessFallbackStrategy getAutoBrightnessFallbackStrategy() { return new AutoBrightnessFallbackStrategy(/* injector= */ null); } + + FallbackBrightnessStrategy getFallbackBrightnessStrategy() { + return new FallbackBrightnessStrategy(); + } } } diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java index 23052286d9ec..f809a49fd3d3 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java +++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java @@ -17,6 +17,9 @@ package com.android.server.display.brightness.strategy; import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; +import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT; +import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE; + import android.annotation.Nullable; import android.content.Context; import android.hardware.display.BrightnessConfiguration; @@ -33,6 +36,7 @@ import com.android.server.display.brightness.BrightnessReason; import com.android.server.display.brightness.BrightnessUtils; import com.android.server.display.brightness.StrategyExecutionRequest; import com.android.server.display.brightness.StrategySelectionNotifyRequest; +import com.android.server.display.feature.DisplayManagerFlags; import java.io.PrintWriter; @@ -98,19 +102,24 @@ public class AutomaticBrightnessStrategy extends AutomaticBrightnessStrategy2 private Injector mInjector; + private DisplayManagerFlags mDisplayManagerFlags; + @VisibleForTesting - AutomaticBrightnessStrategy(Context context, int displayId, Injector injector) { + AutomaticBrightnessStrategy(Context context, int displayId, Injector injector, + DisplayManagerFlags displayManagerFlags) { super(context, displayId); mContext = context; mDisplayId = displayId; mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting(); mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT; mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT; + mDisplayManagerFlags = displayManagerFlags; mInjector = (injector == null) ? new RealInjector() : injector; } - public AutomaticBrightnessStrategy(Context context, int displayId) { - this(context, displayId, null); + public AutomaticBrightnessStrategy(Context context, int displayId, + DisplayManagerFlags displayManagerFlags) { + this(context, displayId, null, displayManagerFlags); } /** @@ -120,6 +129,7 @@ public class AutomaticBrightnessStrategy extends AutomaticBrightnessStrategy2 public void setAutoBrightnessState(int targetDisplayState, boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy, float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) { + switchMode(targetDisplayState); final boolean autoBrightnessEnabledInDoze = allowAutoBrightnessWhileDozingConfig && policy == POLICY_DOZE; mIsAutoBrightnessEnabled = shouldUseAutoBrightness() @@ -479,6 +489,16 @@ public class AutomaticBrightnessStrategy extends AutomaticBrightnessStrategy2 } } + + private void switchMode(int state) { + if (mDisplayManagerFlags.areAutoBrightnessModesEnabled() + && mAutomaticBrightnessController != null + && !mAutomaticBrightnessController.isInIdleMode()) { + mAutomaticBrightnessController.switchMode(Display.isDozeState(state) + ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT); + } + } + /** * Evaluates if there are any temporary auto-brightness adjustments which is not applied yet. * Temporary brightness adjustments happen when the user moves the brightness slider in the diff --git a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java index 504683a55735..7b2f2b9d307b 100644 --- a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java +++ b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategyConstants.java @@ -18,4 +18,5 @@ package com.android.server.display.brightness.strategy; public class DisplayBrightnessStrategyConstants { static final String INVALID_BRIGHTNESS_STRATEGY_NAME = "InvalidBrightnessStrategy"; + public static final String FALLBACK_BRIGHTNESS_STRATEGY_NAME = "FallbackBrightnessStrategy"; } diff --git a/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java new file mode 100644 index 000000000000..3463649aa000 --- /dev/null +++ b/services/core/java/com/android/server/display/brightness/strategy/FallbackBrightnessStrategy.java @@ -0,0 +1,72 @@ +/* + * 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.server.display.brightness.strategy; + +import android.annotation.NonNull; + +import com.android.server.display.DisplayBrightnessState; +import com.android.server.display.brightness.BrightnessReason; +import com.android.server.display.brightness.StrategyExecutionRequest; +import com.android.server.display.brightness.StrategySelectionNotifyRequest; + +import java.io.PrintWriter; + +/** + * Manages the brightness of the associated display when no other strategy qualifies for + * setting up the brightness state. This strategy is also being used for evaluating the + * display brightness state when we have a manually set brightness. This is a temporary state, and + * the logic for evaluating the manual brightness will be moved to a separate strategy + */ +public class FallbackBrightnessStrategy implements DisplayBrightnessStrategy{ + @Override + public DisplayBrightnessState updateBrightness( + StrategyExecutionRequest strategyExecutionRequest) { + BrightnessReason brightnessReason = new BrightnessReason(); + brightnessReason.setReason(BrightnessReason.REASON_MANUAL); + return new DisplayBrightnessState.Builder() + .setBrightness(strategyExecutionRequest.getCurrentScreenBrightness()) + .setSdrBrightness(strategyExecutionRequest.getCurrentScreenBrightness()) + .setBrightnessReason(brightnessReason) + .setDisplayBrightnessStrategyName(getName()) + // The fallback brightness might change due to clamping. Make sure we tell the rest + // of the system by updating the setting + .setShouldUpdateScreenBrightnessSetting(true) + .build(); + } + + @NonNull + @Override + public String getName() { + return DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME; + } + + @Override + public int getReason() { + return BrightnessReason.REASON_MANUAL; + } + + @Override + public void dump(PrintWriter writer) { + + } + + @Override + public void strategySelectionPostProcessor( + StrategySelectionNotifyRequest strategySelectionNotifyRequest) { + + } +} diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java index 816242df639d..c6aef7fb3540 100644 --- a/services/core/java/com/android/server/dreams/DreamController.java +++ b/services/core/java/com/android/server/dreams/DreamController.java @@ -249,14 +249,14 @@ final class DreamController { mCurrentDream.mAppTask = appTask; } - void setDreamHasFocus(boolean hasFocus) { + void setDreamIsObscured(boolean isObscured) { if (mCurrentDream != null) { - mCurrentDream.mDreamHasFocus = hasFocus; + mCurrentDream.mDreamIsObscured = isObscured; } } - boolean dreamHasFocus() { - return mCurrentDream != null && mCurrentDream.mDreamHasFocus; + boolean dreamIsFrontmost() { + return mCurrentDream != null && mCurrentDream.dreamIsFrontmost(); } /** @@ -451,7 +451,7 @@ final class DreamController { private String mStopReason; private long mDreamStartTime; public boolean mWakingGently; - public boolean mDreamHasFocus; + private boolean mDreamIsObscured; private final Runnable mStopPreviousDreamsIfNeeded = this::stopPreviousDreamsIfNeeded; private final Runnable mReleaseWakeLockIfNeeded = this::releaseWakeLockIfNeeded; @@ -549,5 +549,9 @@ final class DreamController { mHandler.removeCallbacks(mReleaseWakeLockIfNeeded); } } + + boolean dreamIsFrontmost() { + return !mDreamIsObscured; + } } } diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index 2def5aed2478..18a9986d34ba 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -20,7 +20,7 @@ import static android.Manifest.permission.BIND_DREAM_SERVICE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; -import static android.service.dreams.Flags.dreamTracksFocus; +import static android.service.dreams.Flags.dreamHandlesBeingObscured; import static com.android.server.wm.ActivityInterceptorCallback.DREAM_MANAGER_ORDERED_ID; @@ -428,7 +428,7 @@ public final class DreamManagerService extends SystemService { // Can't start dreaming if we are already dreaming and the dream has focus. If we are // dreaming but the dream does not have focus, then the dream can be brought to the // front so it does have focus. - if (isScreenOn && isDreamingInternal() && dreamHasFocus()) { + if (isScreenOn && isDreamingInternal() && dreamIsFrontmost()) { return false; } @@ -463,9 +463,10 @@ public final class DreamManagerService extends SystemService { } } - private boolean dreamHasFocus() { - // Dreams always had focus before they were able to track it. - return !dreamTracksFocus() || mController.dreamHasFocus(); + private boolean dreamIsFrontmost() { + // Dreams were always considered frontmost before they began tracking whether they are + // obscured. + return !dreamHandlesBeingObscured() || mController.dreamIsFrontmost(); } protected void requestStartDreamFromShell() { @@ -473,7 +474,7 @@ public final class DreamManagerService extends SystemService { } private void requestDreamInternal() { - if (isDreamingInternal() && !dreamHasFocus() && mController.bringDreamToFront()) { + if (isDreamingInternal() && !dreamIsFrontmost() && mController.bringDreamToFront()) { return; } @@ -1159,10 +1160,16 @@ public final class DreamManagerService extends SystemService { } @Override - public void onDreamFocusChanged(boolean hasFocus) { + public void setDreamIsObscured(boolean isObscured) { + if (!dreamHandlesBeingObscured()) { + return; + } + + checkPermission(android.Manifest.permission.WRITE_DREAM_STATE); + final long ident = Binder.clearCallingIdentity(); try { - mController.setDreamHasFocus(hasFocus); + mHandler.post(() -> mController.setDreamIsObscured(isObscured)); } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/input/InputManagerInternal.java b/services/core/java/com/android/server/input/InputManagerInternal.java index b47631c35e38..d32a5ed60094 100644 --- a/services/core/java/com/android/server/input/InputManagerInternal.java +++ b/services/core/java/com/android/server/input/InputManagerInternal.java @@ -218,4 +218,13 @@ public abstract class InputManagerInternal { * display, external peripherals, fingerprint sensor, etc. */ public abstract void notifyUserActivity(); + + /** + * Get the device ID of the {@link InputDevice} that used most recently. + * + * @return the last used input device ID, or + * {@link android.os.IInputConstants#INVALID_INPUT_DEVICE_ID} if no device has been used + * since boot. + */ + public abstract int getLastUsedInputDeviceId(); } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 83179914c746..8685d2c45762 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -3204,6 +3204,11 @@ public class InputManagerService extends IInputManager.Stub public void setStylusButtonMotionEventsEnabled(boolean enabled) { mNative.setStylusButtonMotionEventsEnabled(enabled); } + + @Override + public int getLastUsedInputDeviceId() { + return mNative.getLastUsedInputDeviceId(); + } } @Override diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java index f742360484f5..0208a325a1d5 100644 --- a/services/core/java/com/android/server/input/NativeInputManagerService.java +++ b/services/core/java/com/android/server/input/NativeInputManagerService.java @@ -271,6 +271,15 @@ interface NativeInputManagerService { void setInputMethodConnectionIsActive(boolean isActive); + /** + * Get the device ID of the InputDevice that used most recently. + * + * @return the last used input device ID, or + * {@link android.os.IInputConstants#INVALID_INPUT_DEVICE_ID} if no device has been used + * since boot. + */ + int getLastUsedInputDeviceId(); + /** The native implementation of InputManagerService methods. */ class NativeImpl implements NativeInputManagerService { /** Pointer to native input manager service object, used by native code. */ @@ -544,5 +553,8 @@ interface NativeInputManagerService { @Override public native void setInputMethodConnectionIsActive(boolean isActive); + + @Override + public native int getLastUsedInputDeviceId(); } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 848f74eb69d7..691145c500d9 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -485,16 +485,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. return userData.mBindingController.getSelectedMethodId(); } - /** - * The current binding sequence number, incremented every time there is - * a new bind performed. - */ - @GuardedBy("ImfLock.class") - private int getSequenceNumberLocked() { - final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); - return userData.mBindingController.getSequenceNumber(); - } - @GuardedBy("ImfLock.class") @Nullable InputMethodInfo queryInputMethodForCurrentUserLocked(@NonNull String imeId) { @@ -543,21 +533,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. EditorInfo mCurEditorInfo; /** - * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently - * connected to or in the process of connecting to. - * - * <p>This can be {@code null} when no input method is connected.</p> - * - * @see #getSelectedMethodIdLocked() - */ - @GuardedBy("ImfLock.class") - @Nullable - private String getCurIdLocked() { - final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); - return userData.mBindingController.getCurId(); - } - - /** * The current subtype of the current input method. */ @MultiUserUnawareField @@ -587,16 +562,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. boolean mInFullscreenMode; /** - * The Intent used to connect to the current input method. - */ - @GuardedBy("ImfLock.class") - @Nullable - private Intent getCurIntentLocked() { - final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); - return userData.mBindingController.getCurIntent(); - } - - /** * The token we have made for the currently active input method, to * identify it in the future. */ @@ -642,15 +607,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. } /** - * If not {@link Process#INVALID_UID}, then the UID of {@link #getCurIntentLocked()}. - */ - @GuardedBy("ImfLock.class") - private int getCurMethodUidLocked() { - final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); - return userData.mBindingController.getCurMethodUid(); - } - - /** * Have we called mCurMethod.bindInput()? */ @MultiUserUnawareField @@ -1915,7 +1871,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. return mClientController.getClient(client.asBinder()); } - // TODO(b/314150112): Move this to ClientController. @GuardedBy("ImfLock.class") void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) { if (mCurClient != null) { @@ -1935,7 +1890,13 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // all accessibility too. That means, when input method get disconnected (including // switching ime), we also unbind accessibility mCurClient.mClient.setActive(false /* active */, false /* fullscreen */); - mCurClient.mClient.onUnbindMethod(getSequenceNumberLocked(), unbindClientReason); + + // TODO(b/325515685): make binding controller user independent. Before this change, the + // following dependencies also need to be user independent: mCurClient, mBoundToMethod, + // getCurMethodLocked(), and mMenuController. + final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); + mCurClient.mClient.onUnbindMethod(userData.mBindingController.getSequenceNumber(), + unbindClientReason); mCurClient.mSessionRequested = false; mCurClient.mSessionRequestedForAccessibility = false; mCurClient = null; @@ -2013,12 +1974,14 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. final boolean restarting = !initial; final Binder startInputToken = new Binder(); + final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); final StartInputInfo info = new StartInputInfo(mCurrentUserId, getCurTokenLocked(), - mCurTokenDisplayId, getCurIdLocked(), startInputReason, restarting, - UserHandle.getUserId(mCurClient.mUid), + mCurTokenDisplayId, userData.mBindingController.getCurId(), startInputReason, + restarting, UserHandle.getUserId(mCurClient.mUid), mCurClient.mSelfReportedDisplayId, mImeBindingState.mFocusedWindow, mCurEditorInfo, - mImeBindingState.mFocusedWindowSoftInputMode, getSequenceNumberLocked()); + mImeBindingState.mFocusedWindowSoftInputMode, + userData.mBindingController.getSequenceNumber()); mImeTargetWindowMap.put(startInputToken, mImeBindingState.mFocusedWindow); mStartInputHistory.addEntry(info); @@ -2029,8 +1992,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case. if (mCurrentUserId == UserHandle.getUserId( mCurClient.mUid)) { - mPackageManagerInternal.grantImplicitAccess(mCurrentUserId, - null /* intent */, UserHandle.getAppId(getCurMethodUidLocked()), + mPackageManagerInternal.grantImplicitAccess(mCurrentUserId, null /* intent */, + UserHandle.getAppId(userData.mBindingController.getCurMethodUid()), mCurClient.mUid, true /* direct */); } @@ -2051,21 +2014,20 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. null /* resultReceiver */, SoftInputShowHideReason.ATTACH_NEW_INPUT); } - String curId = getCurIdLocked(); + final var curId = userData.mBindingController.getCurId(); final InputMethodInfo curInputMethodInfo = InputMethodSettingsRepository.get(mCurrentUserId) .getMethodMap().get(curId); final boolean suppressesSpellChecker = curInputMethodInfo != null && curInputMethodInfo.suppressesSpellChecker(); final SparseArray<IAccessibilityInputMethodSession> accessibilityInputMethodSessions = createAccessibilityInputMethodSessions(mCurClient.mAccessibilitySessions); - final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); if (userData.mBindingController.supportsStylusHandwriting() && hasSupportedStylusLocked()) { mHwController.setInkWindowInitializer(new InkWindowInitializer()); } return new InputBindResult(InputBindResult.ResultCode.SUCCESS_WITH_IME_SESSION, session.mSession, accessibilityInputMethodSessions, (session.mChannel != null ? session.mChannel.dup() : null), - curId, getSequenceNumberLocked(), suppressesSpellChecker); + curId, userData.mBindingController.getSequenceNumber(), suppressesSpellChecker); } @GuardedBy("ImfLock.class") @@ -2341,7 +2303,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. requestClientSessionForAccessibilityLocked(cs); return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_SESSION, - null, null, null, getCurIdLocked(), getSequenceNumberLocked(), false); + null, null, null, + userData.mBindingController.getCurId(), + userData.mBindingController.getSequenceNumber(), false); } else { final long lastBindTime = userData.mBindingController.getLastBindTime(); long bindingDuration = SystemClock.uptimeMillis() - lastBindTime; @@ -2355,7 +2319,9 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // to see if we can get back in touch with the service. return new InputBindResult( InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING, - null, null, null, getCurIdLocked(), getSequenceNumberLocked(), false); + null, null, null, + userData.mBindingController.getCurId(), + userData.mBindingController.getSequenceNumber(), false); } else { EventLog.writeEvent(EventLogTags.IMF_FORCE_RECONNECT_IME, getSelectedMethodIdLocked(), bindingDuration, 0); @@ -2709,7 +2675,8 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // When the IME switcher dialog is shown, the IME switcher button should be hidden. if (mMenuController.getSwitchingDialogLocked() != null) return false; // When we are switching IMEs, the IME switcher button should be hidden. - if (!Objects.equals(getCurIdLocked(), getSelectedMethodIdLocked())) { + final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); + if (!Objects.equals(userData.mBindingController.getCurId(), getSelectedMethodIdLocked())) { return false; } if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded() @@ -2871,8 +2838,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. } else { vis &= ~InputMethodService.IME_VISIBLE_IMPERCEPTIBLE; } + final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); + final var curId = userData.mBindingController.getCurId(); if (mMenuController.getSwitchingDialogLocked() != null - || !Objects.equals(getCurIdLocked(), getSelectedMethodIdLocked())) { + || !Objects.equals(curId, getSelectedMethodIdLocked())) { // When the IME switcher dialog is shown, or we are switching IMEs, // the back button should be in the default state (as if the IME is not shown). backDisposition = InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING; @@ -3567,12 +3536,14 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. "InputMethodManagerService#startInputOrWindowGainedFocus", mDumper); final InputBindResult result; synchronized (ImfLock.class) { + final var userData = mUserDataRepository.getOrCreate(userId); // If the system is not yet ready, we shouldn't be running third party code. if (!mSystemReady) { return new InputBindResult( InputBindResult.ResultCode.ERROR_SYSTEM_NOT_READY, null /* method */, null /* accessibilitySessions */, null /* channel */, - getSelectedMethodIdLocked(), getSequenceNumberLocked(), + getSelectedMethodIdLocked(), + userData.mBindingController.getSequenceNumber(), false /* isInputMethodSuppressingSpellChecker */); } final ClientState cs = mClientController.getClient(client.asBinder()); @@ -3664,7 +3635,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. result = startInputOrWindowGainedFocusInternalLocked(startInputReason, client, windowToken, startInputFlags, softInputMode, windowFlags, editorInfo, inputConnection, remoteAccessibilityInputConnection, - unverifiedTargetSdkVersion, userId, imeDispatcher, cs); + unverifiedTargetSdkVersion, userData, imeDispatcher, cs); } finally { Binder.restoreCallingIdentity(ident); } @@ -3692,7 +3663,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @SoftInputModeFlags int softInputMode, int windowFlags, EditorInfo editorInfo, IRemoteInputConnection inputContext, @Nullable IRemoteAccessibilityInputConnection remoteAccessibilityInputConnection, - int unverifiedTargetSdkVersion, @UserIdInt int userId, + int unverifiedTargetSdkVersion, @NonNull UserDataRepository.UserData userData, @NonNull ImeOnBackInvokedDispatcher imeDispatcher, @NonNull ClientState cs) { if (DEBUG) { Slog.v(TAG, "startInputOrWindowGainedFocusInternalLocked: reason=" @@ -3705,7 +3676,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. + " softInputMode=" + InputMethodDebug.softInputModeToString(softInputMode) + " windowFlags=#" + Integer.toHexString(windowFlags) + " unverifiedTargetSdkVersion=" + unverifiedTargetSdkVersion - + " userId=" + userId + + " userData=" + userData + " imeDispatcher=" + imeDispatcher + " cs=" + cs); } @@ -3724,7 +3695,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. startInputByWinGainedFocus, toolType); mVisibilityStateComputer.setWindowState(windowToken, windowState); - final var userData = mUserDataRepository.getOrCreate(userId); if (sameWindowFocused && isTextEditor) { if (DEBUG) { Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client @@ -3832,10 +3802,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. if (mCurrentUserId != UserHandle.getUserId(uid)) { return false; } - if (getCurIntentLocked() != null && InputMethodUtils.checkIfPackageBelongsToUid( - mPackageManagerInternal, - uid, - getCurIntentLocked().getComponent().getPackageName())) { + final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); + final var curIntent = userData.mBindingController.getCurIntent(); + if (curIntent != null && InputMethodUtils.checkIfPackageBelongsToUid( + mPackageManagerInternal, uid, curIntent.getComponent().getPackageName())) { return true; } return false; @@ -4429,7 +4399,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); final long token = proto.start(fieldId); proto.write(CUR_METHOD_ID, getSelectedMethodIdLocked()); - proto.write(CUR_SEQ, getSequenceNumberLocked()); + proto.write(CUR_SEQ, userData.mBindingController.getSequenceNumber()); proto.write(CUR_CLIENT, Objects.toString(mCurClient)); mImeBindingState.dumpDebug(proto, mWindowManagerInternal); proto.write(LAST_IME_TARGET_WINDOW_NAME, @@ -4439,7 +4409,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. if (mCurEditorInfo != null) { mCurEditorInfo.dumpDebug(proto, CUR_ATTRIBUTE); } - proto.write(CUR_ID, getCurIdLocked()); + proto.write(CUR_ID, userData.mBindingController.getCurId()); mVisibilityStateComputer.dumpDebug(proto, fieldId); proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode); proto.write(CUR_TOKEN, Objects.toString(getCurTokenLocked())); @@ -4896,7 +4866,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. if (mCurClient == null || mCurClient.mClient == null) { return; } - if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol(getCurMethodUidLocked())) { + // TODO(b/325515685): user data must be retrieved by a userId parameter + final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); + if (mImePlatformCompatUtils.shouldUseSetInteractiveProtocol( + userData.mBindingController.getCurMethodUid())) { // Handle IME visibility when interactive changed before finishing the input to // ensure we preserve the last state as possible. final ImeVisibilityResult imeVisRes = mVisibilityStateComputer.onInteractiveChanged( @@ -5626,6 +5599,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. public void onSessionForAccessibilityCreated(int accessibilityConnectionId, IAccessibilityInputMethodSession session, @UserIdInt int userId) { synchronized (ImfLock.class) { + final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); // TODO(b/305829876): Implement user ID verification if (mCurClient != null) { clearClientSessionForAccessibilityLocked(mCurClient, accessibilityConnectionId); @@ -5647,8 +5621,10 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. mCurClient.mAccessibilitySessions); final InputBindResult res = new InputBindResult( InputBindResult.ResultCode.SUCCESS_WITH_ACCESSIBILITY_SESSION, - imeSession, accessibilityInputMethodSessions, null, getCurIdLocked(), - getSequenceNumberLocked(), false); + imeSession, accessibilityInputMethodSessions, /* channel= */ null, + userData.mBindingController.getCurId(), + userData.mBindingController.getSequenceNumber(), + /* isInputMethodSuppressingSpellChecker= */ false); mCurClient.mClient.onBindAccessibilityService(res, accessibilityConnectionId); } } @@ -5658,6 +5634,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. public void unbindAccessibilityFromCurrentClient(int accessibilityConnectionId, @UserIdInt int userId) { synchronized (ImfLock.class) { + final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); // TODO(b/305829876): Implement user ID verification if (mCurClient != null) { if (DEBUG) { @@ -5667,7 +5644,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. // A11yManagerService unbinds the disabled accessibility service. We don't need // to do it here. mCurClient.mClient.onUnbindAccessibilityService( - getSequenceNumberLocked(), + userData.mBindingController.getSequenceNumber(), accessibilityConnectionId); } // We only have sessions when we bound to an input method. Remove this session @@ -5877,13 +5854,11 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. @SuppressWarnings("GuardedBy") Consumer<ClientState> clientControllerDump = c -> { p.println(" " + c + ":"); p.println(" client=" + c.mClient); - p.println(" fallbackInputConnection=" + c.mFallbackInputConnection); p.println(" sessionRequested=" + c.mSessionRequested); - p.println( - " sessionRequestedForAccessibility=" + p.println(" sessionRequestedForAccessibility=" + c.mSessionRequestedForAccessibility); p.println(" curSession=" + c.mCurSession); p.println(" selfReportedDisplayId=" + c.mSelfReportedDisplayId); @@ -5891,14 +5866,16 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. p.println(" pid=" + c.mPid); }; mClientController.forAllClients(clientControllerDump); + final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); p.println(" mCurrentUserId=" + mCurrentUserId); p.println(" mCurMethodId=" + getSelectedMethodIdLocked()); client = mCurClient; - p.println(" mCurClient=" + client + " mCurSeq=" + getSequenceNumberLocked()); + p.println(" mCurClient=" + client + " mCurSeq=" + + userData.mBindingController.getSequenceNumber()); p.println(" mFocusedWindowPerceptible=" + mFocusedWindowPerceptible); mImeBindingState.dump(/* prefix= */ " ", p); - final var userData = mUserDataRepository.getOrCreate(mCurrentUserId); - p.println(" mCurId=" + getCurIdLocked() + + p.println(" mCurId=" + userData.mBindingController.getCurId() + " mHaveConnection=" + userData.mBindingController.hasMainConnection() + " mBoundToMethod=" + mBoundToMethod + " mVisibleBound=" + userData.mBindingController.isVisibleBound()); @@ -5917,7 +5894,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. p.println(" mCurToken=" + getCurTokenLocked()); p.println(" mCurTokenDisplayId=" + mCurTokenDisplayId); p.println(" mCurHostInputToken=" + mAutofillController.getCurHostInputToken()); - p.println(" mCurIntent=" + getCurIntentLocked()); + p.println(" mCurIntent=" + userData.mBindingController.getCurIntent()); method = getCurMethodLocked(); p.println(" mCurMethod=" + getCurMethodLocked()); p.println(" mEnabledSession=" + mEnabledSession); diff --git a/services/core/java/com/android/server/inputmethod/UserDataRepository.java b/services/core/java/com/android/server/inputmethod/UserDataRepository.java index 825cfcbdf505..2b19d3e0a2ea 100644 --- a/services/core/java/com/android/server/inputmethod/UserDataRepository.java +++ b/services/core/java/com/android/server/inputmethod/UserDataRepository.java @@ -96,5 +96,10 @@ final class UserDataRepository { mUserId = userId; mBindingController = bindingController; } + + @Override + public String toString() { + return "UserData{" + "mUserId=" + mUserId + '}'; + } } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index 77a60289d7a9..bf1b3c3f0b35 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -168,6 +168,9 @@ public class KeySyncTask implements Runnable { } private void syncKeys() throws RemoteException { + if (mCredentialUpdated && mRecoverableKeyStoreDb.getBadRemoteGuessCounter(mUserId) != 0) { + mRecoverableKeyStoreDb.setBadRemoteGuessCounter(mUserId, 0); + } int generation = mPlatformKeyManager.getGenerationId(mUserId); if (mCredentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) { // Application keys for the user will not be available for sync. diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 61054a9d4de5..4f87c83bb0d7 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -593,6 +593,8 @@ public class NotificationManagerService extends SystemService { static final long NOTIFICATION_TTL = Duration.ofDays(3).toMillis(); + static final long NOTIFICATION_MAX_AGE_AT_POST = Duration.ofDays(14).toMillis(); + private IActivityManager mAm; private ActivityTaskManagerInternal mAtm; private ActivityManager mActivityManager; @@ -2637,27 +2639,48 @@ public class NotificationManagerService extends SystemService { * Cleanup broadcast receivers change listeners. */ public void onDestroy() { - getContext().unregisterReceiver(mIntentReceiver); - getContext().unregisterReceiver(mPackageIntentReceiver); + if (mIntentReceiver != null) { + getContext().unregisterReceiver(mIntentReceiver); + } + if (mPackageIntentReceiver != null) { + getContext().unregisterReceiver(mPackageIntentReceiver); + } if (Flags.allNotifsNeedTtl()) { - mTtlHelper.destroy(); + if (mTtlHelper != null) { + mTtlHelper.destroy(); + } } else { - getContext().unregisterReceiver(mNotificationTimeoutReceiver); + if (mNotificationTimeoutReceiver != null) { + getContext().unregisterReceiver(mNotificationTimeoutReceiver); + } + } + if (mRestoreReceiver != null) { + getContext().unregisterReceiver(mRestoreReceiver); + } + if (mLocaleChangeReceiver != null) { + getContext().unregisterReceiver(mLocaleChangeReceiver); + } + if (mSettingsObserver != null) { + mSettingsObserver.destroy(); + } + if (mRoleObserver != null) { + mRoleObserver.destroy(); } - getContext().unregisterReceiver(mRestoreReceiver); - getContext().unregisterReceiver(mLocaleChangeReceiver); - - mSettingsObserver.destroy(); - mRoleObserver.destroy(); if (mShortcutHelper != null) { mShortcutHelper.destroy(); } - mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_PREFERENCES); - mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES); - mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES); - mStatsManager.clearPullAtomCallback(DND_MODE_RULE); - mAppOps.stopWatchingMode(mAppOpsListener); - mAlarmManager.cancelAll(); + if (mStatsManager != null) { + mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_PREFERENCES); + mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES); + mStatsManager.clearPullAtomCallback(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES); + mStatsManager.clearPullAtomCallback(DND_MODE_RULE); + } + if (mAppOps != null) { + mAppOps.stopWatchingMode(mAppOpsListener); + } + if (mAlarmManager != null) { + mAlarmManager.cancelAll(); + } } protected String[] getStringArrayResource(int key) { @@ -7722,6 +7745,9 @@ public class NotificationManagerService extends SystemService { return true; } // Check if an app has been given system exemption + if (ai.uid == Process.SYSTEM_UID) { + return false; + } return mAppOps.checkOpNoThrow( AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, ai.packageName) == MODE_ALLOWED; @@ -8016,6 +8042,13 @@ public class NotificationManagerService extends SystemService { return false; } + if (Flags.rejectOldNotifications() && n.hasAppProvidedWhen() && n.getWhen() > 0 + && (System.currentTimeMillis() - n.getWhen()) > NOTIFICATION_MAX_AGE_AT_POST) { + Slog.d(TAG, "Ignored enqueue for old " + n.getWhen() + " notification " + r.getKey()); + mUsageStats.registerTooOldBlocked(r); + return false; + } + return true; } diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java index e960f4ba11fd..c09077e349fd 100644 --- a/services/core/java/com/android/server/notification/NotificationUsageStats.java +++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java @@ -257,6 +257,14 @@ public class NotificationUsageStats { } } + public synchronized void registerTooOldBlocked(NotificationRecord notification) { + AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification); + for (AggregatedStats stats : aggregatedStatsArray) { + stats.numTooOld++; + } + releaseAggregatedStatsLocked(aggregatedStatsArray); + } + @GuardedBy("this") private AggregatedStats[] getAggregatedStatsLocked(NotificationRecord record) { return getAggregatedStatsLocked(record.getSbn().getPackageName()); @@ -405,6 +413,7 @@ public class NotificationUsageStats { public int numUndecoratedRemoteViews; public long mLastAccessTime; public int numImagesRemoved; + public int numTooOld; public AggregatedStats(Context context, String key) { this.key = key; @@ -535,6 +544,7 @@ public class NotificationUsageStats { maybeCount("note_over_alert_rate", (numAlertViolations - previous.numAlertViolations)); maybeCount("note_over_quota", (numQuotaViolations - previous.numQuotaViolations)); maybeCount("note_images_removed", (numImagesRemoved - previous.numImagesRemoved)); + maybeCount("not_too_old", (numTooOld - previous.numTooOld)); noisyImportance.maybeCount(previous.noisyImportance); quietImportance.maybeCount(previous.quietImportance); finalImportance.maybeCount(previous.finalImportance); @@ -570,6 +580,7 @@ public class NotificationUsageStats { previous.numAlertViolations = numAlertViolations; previous.numQuotaViolations = numQuotaViolations; previous.numImagesRemoved = numImagesRemoved; + previous.numTooOld = numTooOld; noisyImportance.update(previous.noisyImportance); quietImportance.update(previous.quietImportance); finalImportance.update(previous.finalImportance); @@ -679,6 +690,8 @@ public class NotificationUsageStats { output.append("numQuotaViolations=").append(numQuotaViolations).append("\n"); output.append(indentPlusTwo); output.append("numImagesRemoved=").append(numImagesRemoved).append("\n"); + output.append(indentPlusTwo); + output.append("numTooOld=").append(numTooOld).append("\n"); output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n"); output.append(indentPlusTwo).append(quietImportance.toString()).append("\n"); output.append(indentPlusTwo).append(finalImportance.toString()).append("\n"); @@ -725,6 +738,7 @@ public class NotificationUsageStats { maybePut(dump, "notificationEnqueueRate", getEnqueueRate()); maybePut(dump, "numAlertViolations", numAlertViolations); maybePut(dump, "numImagesRemoved", numImagesRemoved); + maybePut(dump, "numTooOld", numTooOld); noisyImportance.maybePut(dump, previous.noisyImportance); quietImportance.maybePut(dump, previous.quietImportance); finalImportance.maybePut(dump, previous.finalImportance); diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig index 9dcca494ca24..bf6b6521c19a 100644 --- a/services/core/java/com/android/server/notification/flags.aconfig +++ b/services/core/java/com/android/server/notification/flags.aconfig @@ -135,3 +135,10 @@ flag { description: "This flag controls which signal is used to handle a user switch system event" bug: "337077643" } + +flag { + name: "reject_old_notifications" + namespace: "systemui" + description: "This flag does not allow notifications older than 2 weeks old to be posted" + bug: "339833083" +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java index 99401a17f83c..235e3cd7c9d2 100644 --- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java +++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceManagerService.java @@ -16,6 +16,10 @@ package com.android.server.ondeviceintelligence; +import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_LOADED_BUNDLE_KEY; +import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.MODEL_UNLOADED_BUNDLE_KEY; +import static android.service.ondeviceintelligence.OnDeviceSandboxedInferenceService.REGISTER_MODEL_UPDATE_CALLBACK_BUNDLE_KEY; + import static com.android.server.ondeviceintelligence.BundleUtil.sanitizeInferenceParams; import static com.android.server.ondeviceintelligence.BundleUtil.validatePfdReadOnly; import static com.android.server.ondeviceintelligence.BundleUtil.sanitizeStateParams; @@ -41,6 +45,7 @@ import android.app.ondeviceintelligence.ITokenInfoCallback; import android.app.ondeviceintelligence.OnDeviceIntelligenceException; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.res.Resources; @@ -105,12 +110,20 @@ public class OnDeviceIntelligenceManagerService extends SystemService { /** Handler message to {@link #resetTemporaryServices()} */ private static final int MSG_RESET_TEMPORARY_SERVICE = 0; + /** Handler message to clean up temporary broadcast keys. */ + private static final int MSG_RESET_BROADCAST_KEYS = 1; + /** Default value in absence of {@link DeviceConfig} override. */ private static final boolean DEFAULT_SERVICE_ENABLED = true; private static final String NAMESPACE_ON_DEVICE_INTELLIGENCE = "ondeviceintelligence"; + private static final String SYSTEM_PACKAGE = "android"; + + private final Executor resourceClosingExecutor = Executors.newCachedThreadPool(); private final Executor callbackExecutor = Executors.newCachedThreadPool(); + private final Executor broadcastExecutor = Executors.newCachedThreadPool(); + private final Context mContext; protected final Object mLock = new Object(); @@ -123,10 +136,14 @@ public class OnDeviceIntelligenceManagerService extends SystemService { @GuardedBy("mLock") private String[] mTemporaryServiceNames; + @GuardedBy("mLock") + private String[] mTemporaryBroadcastKeys; + @GuardedBy("mLock") + private String mBroadcastPackageName; + /** * Handler used to reset the temporary service names. */ - @GuardedBy("mLock") private Handler mTemporaryHandler; public OnDeviceIntelligenceManagerService(Context context) { @@ -482,6 +499,8 @@ public class OnDeviceIntelligenceManagerService extends SystemService { ensureRemoteIntelligenceServiceInitialized(); mRemoteOnDeviceIntelligenceService.run( IOnDeviceIntelligenceService::notifyInferenceServiceConnected); + broadcastExecutor.execute( + () -> registerModelLoadingBroadcasts(service)); service.registerRemoteStorageService( getIRemoteStorageService()); } catch (RemoteException ex) { @@ -493,6 +512,56 @@ public class OnDeviceIntelligenceManagerService extends SystemService { } } + private void registerModelLoadingBroadcasts(IOnDeviceSandboxedInferenceService service) { + String[] modelBroadcastKeys; + try { + modelBroadcastKeys = getBroadcastKeys(); + } catch (Resources.NotFoundException e) { + Slog.d(TAG, "Skipping model broadcasts as broadcast intents configured."); + return; + } + + Bundle bundle = new Bundle(); + bundle.putBoolean(REGISTER_MODEL_UPDATE_CALLBACK_BUNDLE_KEY, true); + try { + service.updateProcessingState(bundle, new IProcessingUpdateStatusCallback.Stub() { + @Override + public void onSuccess(PersistableBundle statusParams) { + Binder.clearCallingIdentity(); + synchronized (mLock) { + if (statusParams.containsKey(MODEL_LOADED_BUNDLE_KEY)) { + String modelLoadedBroadcastKey = modelBroadcastKeys[0]; + if (modelLoadedBroadcastKey != null + && !modelLoadedBroadcastKey.isEmpty()) { + final Intent intent = new Intent(modelLoadedBroadcastKey); + intent.setPackage(mBroadcastPackageName); + mContext.sendBroadcast(intent, + Manifest.permission.USE_ON_DEVICE_INTELLIGENCE); + } + } else if (statusParams.containsKey(MODEL_UNLOADED_BUNDLE_KEY)) { + String modelUnloadedBroadcastKey = modelBroadcastKeys[1]; + if (modelUnloadedBroadcastKey != null + && !modelUnloadedBroadcastKey.isEmpty()) { + final Intent intent = new Intent(modelUnloadedBroadcastKey); + intent.setPackage(mBroadcastPackageName); + mContext.sendBroadcast(intent, + Manifest.permission.USE_ON_DEVICE_INTELLIGENCE); + } + } + } + } + + @Override + public void onFailure(int errorCode, String errorMessage) { + Slog.e(TAG, "Failed to register model loading callback with status code", + new OnDeviceIntelligenceException(errorCode, errorMessage)); + } + }); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to register model loading callback with status code", e); + } + } + @NonNull private IRemoteStorageService.Stub getIRemoteStorageService() { return new IRemoteStorageService.Stub() { @@ -629,6 +698,20 @@ public class OnDeviceIntelligenceManagerService extends SystemService { R.string.config_defaultOnDeviceSandboxedInferenceService)}; } + protected String[] getBroadcastKeys() throws Resources.NotFoundException { + // TODO 329240495 : Consider a small class with explicit field names for the two services + synchronized (mLock) { + if (mTemporaryBroadcastKeys != null && mTemporaryBroadcastKeys.length == 2) { + return mTemporaryBroadcastKeys; + } + } + + return new String[]{mContext.getResources().getString( + R.string.config_onDeviceIntelligenceModelLoadedBroadcastKey), + mContext.getResources().getString( + R.string.config_onDeviceIntelligenceModelUnloadedBroadcastKey)}; + } + @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) public void setTemporaryServices(@NonNull String[] componentNames, int durationMs) { Objects.requireNonNull(componentNames); @@ -645,25 +728,26 @@ public class OnDeviceIntelligenceManagerService extends SystemService { mRemoteOnDeviceIntelligenceService.unbind(); mRemoteOnDeviceIntelligenceService = null; } - if (mTemporaryHandler == null) { - mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) { - @Override - public void handleMessage(Message msg) { - if (msg.what == MSG_RESET_TEMPORARY_SERVICE) { - synchronized (mLock) { - resetTemporaryServices(); - } - } else { - Slog.wtf(TAG, "invalid handler msg: " + msg); - } - } - }; - } else { - mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE); + + if (durationMs != -1) { + getTemporaryHandler().sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, + durationMs); } + } + } + @RequiresPermission(Manifest.permission.USE_ON_DEVICE_INTELLIGENCE) + public void setModelBroadcastKeys(@NonNull String[] broadcastKeys, String receiverPackageName, + int durationMs) { + Objects.requireNonNull(broadcastKeys); + enforceShellOnly(Binder.getCallingUid(), "setModelBroadcastKeys"); + mContext.enforceCallingPermission( + Manifest.permission.USE_ON_DEVICE_INTELLIGENCE, TAG); + synchronized (mLock) { + mTemporaryBroadcastKeys = broadcastKeys; + mBroadcastPackageName = receiverPackageName; if (durationMs != -1) { - mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs); + getTemporaryHandler().sendEmptyMessageDelayed(MSG_RESET_BROADCAST_KEYS, durationMs); } } } @@ -751,4 +835,28 @@ public class OnDeviceIntelligenceManagerService extends SystemService { } } } + + private synchronized Handler getTemporaryHandler() { + if (mTemporaryHandler == null) { + mTemporaryHandler = new Handler(Looper.getMainLooper(), null, true) { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_RESET_TEMPORARY_SERVICE) { + synchronized (mLock) { + resetTemporaryServices(); + } + } else if (msg.what == MSG_RESET_BROADCAST_KEYS) { + synchronized (mLock) { + mTemporaryBroadcastKeys = null; + mBroadcastPackageName = SYSTEM_PACKAGE; + } + } else { + Slog.wtf(TAG, "invalid handler msg: " + msg); + } + } + }; + } + + return mTemporaryHandler; + } } diff --git a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java index a76d8a31405d..5744b5c3c2c4 100644 --- a/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java +++ b/services/core/java/com/android/server/ondeviceintelligence/OnDeviceIntelligenceShellCommand.java @@ -43,6 +43,8 @@ final class OnDeviceIntelligenceShellCommand extends ShellCommand { return setTemporaryServices(); case "get-services": return getConfiguredServices(); + case "set-model-broadcasts": + return setBroadcastKeys(); default: return handleDefaultCommands(cmd); } @@ -62,12 +64,18 @@ final class OnDeviceIntelligenceShellCommand extends ShellCommand { pw.println(" To reset, call without any arguments."); pw.println(" get-services To get the names of services that are currently being used."); + pw.println( + " set-model-broadcasts [ModelLoadedBroadcastKey] [ModelUnloadedBroadcastKey] " + + "[ReceiverPackageName] " + + "[DURATION] To set the names of broadcast intent keys that are to be " + + "emitted for cts tests."); } private int setTemporaryServices() { final PrintWriter out = getOutPrintWriter(); final String intelligenceServiceName = getNextArg(); final String inferenceServiceName = getNextArg(); + if (getRemainingArgsCount() == 0 && intelligenceServiceName == null && inferenceServiceName == null) { mService.resetTemporaryServices(); @@ -79,7 +87,8 @@ final class OnDeviceIntelligenceShellCommand extends ShellCommand { Objects.requireNonNull(inferenceServiceName); final int duration = Integer.parseInt(getNextArgRequired()); mService.setTemporaryServices( - new String[]{intelligenceServiceName, inferenceServiceName}, duration); + new String[]{intelligenceServiceName, inferenceServiceName}, + duration); out.println("OnDeviceIntelligenceService temporarily set to " + intelligenceServiceName + " \n and \n OnDeviceTrustedInferenceService set to " + inferenceServiceName + " for " + duration + "ms"); @@ -93,4 +102,22 @@ final class OnDeviceIntelligenceShellCommand extends ShellCommand { + " \n and \n OnDeviceTrustedInferenceService set to : " + services[1]); return 0; } + + private int setBroadcastKeys() { + final PrintWriter out = getOutPrintWriter(); + final String modelLoadedKey = getNextArgRequired(); + final String modelUnloadedKey = getNextArgRequired(); + final String receiverPackageName = getNextArg(); + + final int duration = Integer.parseInt(getNextArgRequired()); + mService.setModelBroadcastKeys( + new String[]{modelLoadedKey, modelUnloadedKey}, receiverPackageName, duration); + out.println("OnDeviceIntelligence Model Loading broadcast keys temporarily set to " + + modelLoadedKey + + " \n and \n OnDeviceTrustedInferenceService set to " + modelUnloadedKey + + "\n and Package name set to : " + receiverPackageName + + " for " + duration + "ms"); + return 0; + } + }
\ No newline at end of file diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java index 9ba88aa18ce6..fe774aa75efc 100644 --- a/services/core/java/com/android/server/pm/AppDataHelper.java +++ b/services/core/java/com/android/server/pm/AppDataHelper.java @@ -504,9 +504,12 @@ public class AppDataHelper { } else { storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE; } - List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, - UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */, - true /* onlyCoreApps */); + final List<String> deferPackages; + synchronized (mPm.mInstallLock) { + deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, + UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */, + true /* onlyCoreApps */); + } Future<?> prepareAppDataFuture = SystemServerInitThreadPool.submit(() -> { TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync", Trace.TRACE_TAG_PACKAGE_MANAGER); diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 19a0ba796343..908b47df35e1 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -985,13 +985,13 @@ final class InstallPackageHelper { } void installPackagesTraced(List<InstallRequest> requests) { - synchronized (mPm.mInstallLock) { - try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); - installPackagesLI(requests); - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } + mPm.mInstallLock.lock(); + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages"); + installPackagesLI(requests); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + mPm.mInstallLock.unlock(); } } @@ -2590,22 +2590,30 @@ final class InstallPackageHelper { final boolean performDexopt = DexOptHelper.shouldPerformDexopt(installRequest, dexoptOptions, mContext); if (performDexopt) { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); + // dexopt can take long, and ArtService doesn't require installd, so we release + // the lock here and re-acquire the lock after dexopt is finished. + mPm.mInstallLock.unlock(); + try { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); - // This mirrors logic from commitReconciledScanResultLocked, where the library files - // needed for dexopt are assigned. - PackageSetting realPkgSetting = installRequest.getRealPackageSetting(); + // This mirrors logic from commitReconciledScanResultLocked, where the library + // files needed for dexopt are assigned. + PackageSetting realPkgSetting = installRequest.getRealPackageSetting(); - // Unfortunately, the updated system app flag is only tracked on this PackageSetting - boolean isUpdatedSystemApp = - installRequest.getScannedPackageSetting().isUpdatedSystemApp(); + // Unfortunately, the updated system app flag is only tracked on this + // PackageSetting + boolean isUpdatedSystemApp = + installRequest.getScannedPackageSetting().isUpdatedSystemApp(); - realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp); + realPkgSetting.getPkgState().setUpdatedSystemApp(isUpdatedSystemApp); - DexoptResult dexOptResult = - DexOptHelper.dexoptPackageUsingArtService(installRequest, dexoptOptions); - installRequest.onDexoptFinished(dexOptResult); - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + DexoptResult dexOptResult = DexOptHelper.dexoptPackageUsingArtService( + installRequest, dexoptOptions); + installRequest.onDexoptFinished(dexOptResult); + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } finally { + mPm.mInstallLock.lock(); + } } } PackageManagerServiceUtils.waitForNativeBinariesExtractionForIncremental( diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ae485ede1bec..121cf3f231b0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -626,7 +626,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService // Lock for state used when installing and doing other long running // operations. Methods that must be called with this lock held have // the suffix "LI". - final Object mInstallLock; + final PackageManagerTracedLock mInstallLock; // ---------------------------------------------------------------- @@ -1692,8 +1692,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", Trace.TRACE_TAG_PACKAGE_MANAGER); t.traceBegin("create package manager"); - final PackageManagerTracedLock lock = new PackageManagerTracedLock(); - final Object installLock = new Object(); + final PackageManagerTracedLock lock = new PackageManagerTracedLock("mLock"); + final PackageManagerTracedLock installLock = new PackageManagerTracedLock("mInstallLock"); HandlerThread backgroundThread = new ServiceThread("PackageManagerBg", Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/); diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java index 83f3b16b31d1..ae2eaeb31f81 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceInjector.java @@ -86,7 +86,7 @@ public class PackageManagerServiceInjector { private final Context mContext; private final PackageManagerTracedLock mLock; private final Installer mInstaller; - private final Object mInstallLock; + private final PackageManagerTracedLock mInstallLock; private final Handler mBackgroundHandler; private final Executor mBackgroundExecutor; private final List<ScanPartition> mSystemPartitions; @@ -144,7 +144,7 @@ public class PackageManagerServiceInjector { private final Singleton<PackageMonitorCallbackHelper> mPackageMonitorCallbackHelper; PackageManagerServiceInjector(Context context, PackageManagerTracedLock lock, - Installer installer, Object installLock, PackageAbiHelper abiHelper, + Installer installer, PackageManagerTracedLock installLock, PackageAbiHelper abiHelper, Handler backgroundHandler, List<ScanPartition> systemPartitions, Producer<ComponentResolver> componentResolverProducer, @@ -254,7 +254,7 @@ public class PackageManagerServiceInjector { return mAbiHelper; } - public Object getInstallLock() { + public PackageManagerTracedLock getInstallLock() { return mInstallLock; } diff --git a/services/core/java/com/android/server/pm/PackageManagerTracedLock.java b/services/core/java/com/android/server/pm/PackageManagerTracedLock.java index 75e1803f1695..303b8b9dd817 100644 --- a/services/core/java/com/android/server/pm/PackageManagerTracedLock.java +++ b/services/core/java/com/android/server/pm/PackageManagerTracedLock.java @@ -16,6 +16,9 @@ package com.android.server.pm; +import android.annotation.Nullable; +import android.util.Slog; + import java.util.concurrent.locks.ReentrantLock; /** @@ -23,4 +26,31 @@ import java.util.concurrent.locks.ReentrantLock; * injection, similar to {@link ActivityManagerGlobalLock}. */ public class PackageManagerTracedLock extends ReentrantLock { + private static final String TAG = "PackageManagerTracedLock"; + private static final boolean DEBUG = false; + @Nullable private final String mLockName; + + public PackageManagerTracedLock(@Nullable String lockName) { + mLockName = lockName; + } + + public PackageManagerTracedLock() { + this(null); + } + + @Override + public void lock() { + super.lock(); + if (DEBUG && mLockName != null) { + Slog.i(TAG, "locked " + mLockName); + } + } + + @Override + public void unlock() { + super.unlock(); + if (DEBUG && mLockName != null) { + Slog.i(TAG, "unlocked " + mLockName); + } + } } diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java index 3a0f7fb4b432..02bd3cca5eb4 100644 --- a/services/core/java/com/android/server/pm/RemovePackageHelper.java +++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java @@ -376,11 +376,14 @@ final class RemovePackageHelper { @NonNull PackageRemovedInfo outInfo, int flags, boolean writeSettings) { String packageName = deletedPs.getPackageName(); if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + deletedPs); + final boolean shouldDeletePackageSetting = + shouldDeletePackageSetting(deletedPs, targetUserId, allUserHandles, flags); // Retrieve object to delete permissions for shared user later on final AndroidPackage deletedPkg = deletedPs.getPkg(); // Delete all the data and states related to this package. - clearPackageStateForUserLIF(deletedPs, targetUserId, flags); + clearPackageStateForUserLIF(deletedPs, + shouldDeletePackageSetting ? UserHandle.USER_ALL : targetUserId, flags); // Delete from mPackages removePackageLI(packageName, (flags & PackageManager.DELETE_CHATTY) != 0); @@ -392,7 +395,7 @@ final class RemovePackageHelper { deletedPs.setPkg(null); } - if (shouldDeletePackageSetting(deletedPs, targetUserId, allUserHandles, flags)) { + if (shouldDeletePackageSetting) { // Delete from mSettings final SparseBooleanArray changedUsers = new SparseBooleanArray(); synchronized (mPm.mLock) { diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java index 1d414011cff3..ef32485567f8 100644 --- a/services/core/java/com/android/server/pm/UserDataPreparer.java +++ b/services/core/java/com/android/server/pm/UserDataPreparer.java @@ -52,11 +52,11 @@ class UserDataPreparer { private static final String TAG = "UserDataPreparer"; private static final String XATTR_SERIAL = "user.serial"; - private final Object mInstallLock; + private final PackageManagerTracedLock mInstallLock; private final Context mContext; private final Installer mInstaller; - UserDataPreparer(Installer installer, Object installLock, Context context) { + UserDataPreparer(Installer installer, PackageManagerTracedLock installLock, Context context) { mInstallLock = installLock; mContext = context; mInstaller = installer; diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index f6487ceea43b..b1976cd0d13b 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1371,7 +1371,7 @@ public class UserManagerService extends IUserManager.Stub { for (int i = 0; i < userSize; i++) { UserInfo ui = mUsers.valueAt(i).info; if ((excludePartial && ui.partial) - || (excludeDying && isDyingLU(ui)) + || (excludeDying && mRemovingUserIds.get(ui.id)) || (excludePreCreated && ui.preCreated)) { continue; } @@ -1381,17 +1381,6 @@ public class UserManagerService extends IUserManager.Stub { } } - @GuardedBy("mUsersLock") - private boolean isDyingLU(UserInfo ui) { - if (mRemovingUserIds.get(ui.id)) { - return true; - } - if (ui.isEphemeral() && ui.isInitialized() && ui.id != getCurrentUserId()) { - return true; - } - return false; - } - @Override public List<UserInfo> getProfiles(@UserIdInt int userId, boolean enabledOnly) { boolean returnFullInfo; diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index 93f26aefb692..c85ceac9ea55 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -642,6 +642,8 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve .getPackages() .get(0) .getVersionRolledBackFrom(); + Slog.i(TAG, "Rolling back high impact rollback for package: " + + firstRollback.getPackageName()); rollbackPackage(sortedHighImpactRollbacks.get(0), firstRollback, rollbackReason); } diff --git a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java index 519c0edfc532..7fc02923bfed 100644 --- a/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java +++ b/services/core/java/com/android/server/rollback/WatchdogRollbackLogger.java @@ -293,6 +293,8 @@ public final class WatchdogRollbackLogger { return "REASON_APP_NOT_RESPONDING"; case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_NATIVE_CRASH_DURING_BOOT: return "REASON_NATIVE_CRASH_DURING_BOOT"; + case WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_REASON__REASON_BOOT_LOOPING: + return "REASON_BOOT_LOOP"; default: return "UNKNOWN"; } diff --git a/services/core/java/com/android/server/security/AttestationVerificationManagerService.java b/services/core/java/com/android/server/security/AttestationVerificationManagerService.java index 2bf0b2cd4f4a..55f85ea27c82 100644 --- a/services/core/java/com/android/server/security/AttestationVerificationManagerService.java +++ b/services/core/java/com/android/server/security/AttestationVerificationManagerService.java @@ -22,6 +22,8 @@ import static android.security.attestationverification.AttestationVerificationMa import static android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE; import static android.security.attestationverification.AttestationVerificationManager.RESULT_UNKNOWN; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.os.Bundle; import android.os.IBinder; @@ -31,12 +33,20 @@ import android.security.attestationverification.AttestationProfile; import android.security.attestationverification.IAttestationVerificationManagerService; import android.security.attestationverification.IVerificationResult; import android.security.attestationverification.VerificationToken; +import android.text.TextUtils; import android.util.ExceptionUtils; +import android.util.IndentingPrintWriter; import android.util.Slog; +import android.util.TimeUtils; import com.android.internal.infra.AndroidFuture; +import com.android.internal.util.DumpUtils; import com.android.server.SystemService; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayDeque; + /** * A {@link SystemService} which provides functionality related to verifying attestations of * (usually) remote computing environments. @@ -46,11 +56,13 @@ import com.android.server.SystemService; public class AttestationVerificationManagerService extends SystemService { private static final String TAG = "AVF"; + private static final int DUMP_EVENT_LOG_SIZE = 10; private final AttestationVerificationPeerDeviceVerifier mPeerDeviceVerifier; + private final DumpLogger mDumpLogger = new DumpLogger(); public AttestationVerificationManagerService(final Context context) throws Exception { super(context); - mPeerDeviceVerifier = new AttestationVerificationPeerDeviceVerifier(context); + mPeerDeviceVerifier = new AttestationVerificationPeerDeviceVerifier(context, mDumpLogger); } private final IBinder mService = new IAttestationVerificationManagerService.Stub() { @@ -83,6 +95,28 @@ public class AttestationVerificationManagerService extends SystemService { private void enforceUsePermission() { getContext().enforceCallingOrSelfPermission(USE_ATTESTATION_VERIFICATION_SERVICE, null); } + + @Override + protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, + @Nullable String[] args) { + if (!android.security.Flags.dumpAttestationVerifications()) { + super.dump(fd, writer, args); + return; + } + + if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, writer)) return; + + final IndentingPrintWriter fout = new IndentingPrintWriter(writer, " "); + + fout.print("AttestationVerificationManagerService"); + fout.println(); + fout.increaseIndent(); + + fout.println("Event Log:"); + fout.increaseIndent(); + mDumpLogger.dumpTo(fout); + fout.decreaseIndent(); + } }; private void verifyAttestationForAllVerifiers( @@ -119,4 +153,45 @@ public class AttestationVerificationManagerService extends SystemService { Slog.d(TAG, "Started"); publishBinderService(Context.ATTESTATION_VERIFICATION_SERVICE, mService); } + + + static class DumpLogger { + private final ArrayDeque<DumpData> mData = new ArrayDeque<>(DUMP_EVENT_LOG_SIZE); + private int mEventsLogged = 0; + + void logAttempt(DumpData data) { + synchronized (mData) { + if (mData.size() == DUMP_EVENT_LOG_SIZE) { + mData.removeFirst(); + } + + mEventsLogged++; + data.mEventNumber = mEventsLogged; + + data.mEventTimeMs = System.currentTimeMillis(); + + mData.add(data); + } + } + + void dumpTo(IndentingPrintWriter writer) { + synchronized (mData) { + for (DumpData data : mData.reversed()) { + writer.println( + TextUtils.formatSimple("Verification #%d [%s]", data.mEventNumber, + TimeUtils.formatForLogging(data.mEventTimeMs))); + writer.increaseIndent(); + data.dumpTo(writer); + writer.decreaseIndent(); + } + } + } + } + + abstract static class DumpData { + protected int mEventNumber = -1; + protected long mEventTimeMs = -1; + + abstract void dumpTo(IndentingPrintWriter writer); + } } diff --git a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java index 72a402d7a58c..945a3400d971 100644 --- a/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java +++ b/services/core/java/com/android/server/security/AttestationVerificationPeerDeviceVerifier.java @@ -30,15 +30,19 @@ import static com.android.server.security.AndroidKeystoreAttestationVerification import static java.nio.charset.StandardCharsets.UTF_8; import android.annotation.NonNull; +import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; import android.os.Bundle; +import android.security.attestationverification.AttestationVerificationManager; import android.security.attestationverification.AttestationVerificationManager.LocalBindingType; +import android.util.IndentingPrintWriter; import android.util.Log; import android.util.Slog; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.security.AttestationVerificationManagerService.DumpLogger; import org.json.JSONObject; @@ -71,7 +75,9 @@ import java.util.Set; /** * Verifies Android key attestation according to the - * {@link android.security.attestationverification.AttestationVerificationManager#PROFILE_PEER_DEVICE PROFILE_PEER_DEVICE} + * {@link + * android.security.attestationverification.AttestationVerificationManager#PROFILE_PEER_DEVICE + * PROFILE_PEER_DEVICE} * profile. * * <p> @@ -118,9 +124,12 @@ class AttestationVerificationPeerDeviceVerifier { private final LocalDate mTestLocalPatchDate; private final CertificateFactory mCertificateFactory; private final CertPathValidator mCertPathValidator; + private final DumpLogger mDumpLogger; - AttestationVerificationPeerDeviceVerifier(@NonNull Context context) throws Exception { + AttestationVerificationPeerDeviceVerifier(@NonNull Context context, + @NonNull DumpLogger dumpLogger) throws Exception { mContext = Objects.requireNonNull(context); + mDumpLogger = dumpLogger; mCertificateFactory = CertificateFactory.getInstance("X.509"); mCertPathValidator = CertPathValidator.getInstance("PKIX"); mTrustAnchors = getTrustAnchors(); @@ -132,9 +141,10 @@ class AttestationVerificationPeerDeviceVerifier { // Use ONLY for hermetic unit testing. @VisibleForTesting AttestationVerificationPeerDeviceVerifier(@NonNull Context context, - Set<TrustAnchor> trustAnchors, boolean revocationEnabled, + DumpLogger dumpLogger, Set<TrustAnchor> trustAnchors, boolean revocationEnabled, LocalDate systemDate, LocalDate localPatchDate) throws Exception { mContext = Objects.requireNonNull(context); + mDumpLogger = dumpLogger; mCertificateFactory = CertificateFactory.getInstance("X.509"); mCertPathValidator = CertPathValidator.getInstance("PKIX"); mTrustAnchors = trustAnchors; @@ -153,63 +163,90 @@ class AttestationVerificationPeerDeviceVerifier { * bounded at the end by {@code -----END CERTIFICATE-----}. * * @param localBindingType Only {@code TYPE_PUBLIC_KEY} and {@code TYPE_CHALLENGE} supported. - * @param requirements Only {@code PARAM_PUBLIC_KEY} and {@code PARAM_CHALLENGE} supported. - * @param attestation Certificates should be DER encoded with leaf certificate appended first. + * @param requirements Only {@code PARAM_PUBLIC_KEY} and {@code PARAM_CHALLENGE} supported. + * @param attestation Certificates should be DER encoded with leaf certificate appended + * first. */ int verifyAttestation( @LocalBindingType int localBindingType, @NonNull Bundle requirements, @NonNull byte[] attestation) { + + MyDumpData dumpData = new MyDumpData(); + + int result = + verifyAttestationInternal(localBindingType, requirements, attestation, dumpData); + dumpData.mResult = result; + mDumpLogger.logAttempt(dumpData); + return result; + } + + private int verifyAttestationInternal( + @LocalBindingType int localBindingType, + @NonNull Bundle requirements, + @NonNull byte[] attestation, + @NonNull MyDumpData dumpData) { if (mCertificateFactory == null) { debugVerboseLog("Unable to access CertificateFactory"); return RESULT_FAILURE; } + dumpData.mCertificationFactoryAvailable = true; if (mCertPathValidator == null) { debugVerboseLog("Unable to access CertPathValidator"); return RESULT_FAILURE; } + dumpData.mCertPathValidatorAvailable = true; + // Check if the provided local binding type is supported and if the provided requirements // "match" the binding type. if (!validateAttestationParameters(localBindingType, requirements)) { return RESULT_FAILURE; } + dumpData.mAttestationParametersOk = true; + + // To provide the most information in the dump logs, we track the failure state but keep + // verifying the rest of the attestation. For code safety, there are no transitions past + // here to set failed = false + boolean failed = false; try { // First: parse and validate the certificate chain. final List<X509Certificate> certificateChain = getCertificates(attestation); // (returns void, but throws CertificateException and other similar Exceptions) validateCertificateChain(certificateChain); + dumpData.mCertChainOk = true; final var leafCertificate = certificateChain.get(0); final var attestationExtension = fromCertificate(leafCertificate); // Second: verify if the attestation satisfies the "peer device" profile. - if (!checkAttestationForPeerDeviceProfile(attestationExtension)) { - return RESULT_FAILURE; + if (!checkAttestationForPeerDeviceProfile(attestationExtension, dumpData)) { + failed = true; } // Third: check if the attestation satisfies local binding requirements. if (!checkLocalBindingRequirements( - leafCertificate, attestationExtension, localBindingType, requirements)) { - return RESULT_FAILURE; + leafCertificate, attestationExtension, localBindingType, requirements, + dumpData)) { + failed = true; } - - return RESULT_SUCCESS; } catch (CertificateException | CertPathValidatorException - | InvalidAlgorithmParameterException | IOException e) { + | InvalidAlgorithmParameterException | IOException e) { // Catch all non-RuntimeExpceptions (all of these are thrown by either getCertificates() // or validateCertificateChain() or // AndroidKeystoreAttestationVerificationAttributes.fromCertificate()) debugVerboseLog("Unable to parse/validate Android Attestation certificate(s)", e); - return RESULT_FAILURE; + failed = true; } catch (RuntimeException e) { // Catch everyting else (RuntimeExpcetions), since we don't want to throw any exceptions // out of this class/method. debugVerboseLog("Unexpected error", e); - return RESULT_FAILURE; + failed = true; } + + return failed ? RESULT_FAILURE : RESULT_SUCCESS; } @NonNull @@ -255,7 +292,7 @@ class AttestationVerificationPeerDeviceVerifier { private void validateCertificateChain(List<X509Certificate> certificates) throws CertificateException, CertPathValidatorException, - InvalidAlgorithmParameterException { + InvalidAlgorithmParameterException { if (certificates.size() < 2) { debugVerboseLog("Certificate chain less than 2 in size."); throw new CertificateException("Certificate chain less than 2 in size."); @@ -277,7 +314,7 @@ class AttestationVerificationPeerDeviceVerifier { private Set<TrustAnchor> getTrustAnchors() throws CertPathValidatorException { Set<TrustAnchor> modifiableSet = new HashSet<>(); try { - for (String certString: getTrustAnchorResources()) { + for (String certString : getTrustAnchorResources()) { modifiableSet.add( new TrustAnchor((X509Certificate) mCertificateFactory.generateCertificate( new ByteArrayInputStream(getCertificateBytes(certString))), null)); @@ -307,8 +344,9 @@ class AttestationVerificationPeerDeviceVerifier { @NonNull X509Certificate leafCertificate, @NonNull AndroidKeystoreAttestationVerificationAttributes attestationAttributes, @LocalBindingType int localBindingType, - @NonNull Bundle requirements) { + @NonNull Bundle requirements, MyDumpData dumpData) { // First: check non-optional (for the given local binding type) requirements. + dumpData.mBindingType = localBindingType; switch (localBindingType) { case TYPE_PUBLIC_KEY: // Verify leaf public key matches provided public key. @@ -336,9 +374,11 @@ class AttestationVerificationPeerDeviceVerifier { throw new IllegalArgumentException("Unsupported local binding type " + localBindingTypeToString(localBindingType)); } + dumpData.mBindingOk = true; // Second: check specified optional requirements. if (requirements.containsKey(PARAM_OWNED_BY_SYSTEM)) { + dumpData.mSystemOwnershipChecked = true; if (requirements.getBoolean(PARAM_OWNED_BY_SYSTEM)) { // Verify key is owned by the system. final boolean ownedBySystem = checkOwnedBySystem( @@ -347,6 +387,7 @@ class AttestationVerificationPeerDeviceVerifier { debugVerboseLog("Certificate public key is not owned by the AndroidSystem."); return false; } + dumpData.mSystemOwned = true; } else { throw new IllegalArgumentException("The value of the requirement key " + PARAM_OWNED_BY_SYSTEM @@ -359,73 +400,98 @@ class AttestationVerificationPeerDeviceVerifier { } private boolean checkAttestationForPeerDeviceProfile( - @NonNull AndroidKeystoreAttestationVerificationAttributes attestationAttributes) { + @NonNull AndroidKeystoreAttestationVerificationAttributes attestationAttributes, + MyDumpData dumpData) { + boolean result = true; + // Checks for support of Keymaster 4. if (attestationAttributes.getAttestationVersion() < 3) { debugVerboseLog("Attestation version is not at least 3 (Keymaster 4)."); - return false; + result = false; + } else { + dumpData.mAttestationVersionAtLeast3 = true; } // Checks for support of Keymaster 4. if (attestationAttributes.getKeymasterVersion() < 4) { debugVerboseLog("Keymaster version is not at least 4."); - return false; + result = false; + } else { + dumpData.mKeymasterVersionAtLeast4 = true; } // First two characters are Android OS version. if (attestationAttributes.getKeyOsVersion() < 100000) { debugVerboseLog("Android OS version is not 10+."); - return false; + result = false; + } else { + dumpData.mOsVersionAtLeast10 = true; } if (!attestationAttributes.isAttestationHardwareBacked()) { debugVerboseLog("Key is not HW backed."); - return false; + result = false; + } else { + dumpData.mKeyHwBacked = true; } if (!attestationAttributes.isKeymasterHardwareBacked()) { debugVerboseLog("Keymaster is not HW backed."); - return false; + result = false; + } else { + dumpData.mKeymasterHwBacked = true; } if (attestationAttributes.getVerifiedBootState() != VERIFIED) { debugVerboseLog("Boot state not Verified."); - return false; + result = false; + } else { + dumpData.mBootStateIsVerified = true; } try { if (!attestationAttributes.isVerifiedBootLocked()) { debugVerboseLog("Verified boot state is not locked."); - return false; + result = false; + } else { + dumpData.mVerifiedBootStateLocked = true; } } catch (IllegalStateException e) { debugVerboseLog("VerifiedBootLocked is not set.", e); - return false; + result = false; } // Patch level integer YYYYMM is expected to be within 1 year of today. if (!isValidPatchLevel(attestationAttributes.getKeyOsPatchLevel())) { debugVerboseLog("OS patch level is not within valid range."); - return false; + result = false; + } else { + dumpData.mOsPatchLevelInRange = true; } // Patch level integer YYYYMMDD is expected to be within 1 year of today. if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel())) { debugVerboseLog("Boot patch level is not within valid range."); - return false; + result = false; + } else { + dumpData.mKeyBootPatchLevelInRange = true; } if (!isValidPatchLevel(attestationAttributes.getKeyVendorPatchLevel())) { debugVerboseLog("Vendor patch level is not within valid range."); - return false; + result = false; + } else { + dumpData.mKeyVendorPatchLevelInRange = true; } if (!isValidPatchLevel(attestationAttributes.getKeyBootPatchLevel())) { debugVerboseLog("Boot patch level is not within valid range."); - return false; + result = false; + } else { + dumpData.mKeyBootPatchLevelInRange = true; } - return true; + return result; } private boolean checkPublicKey( @@ -609,4 +675,99 @@ class AttestationVerificationPeerDeviceVerifier { Slog.v(TAG, str); } } + + /* Mutable data class for tracking dump data from verifications. */ + private static class MyDumpData extends AttestationVerificationManagerService.DumpData { + + // Top-Level Result + int mResult = -1; + + // Configuration/Setup preconditions + boolean mCertificationFactoryAvailable = false; + boolean mCertPathValidatorAvailable = false; + + // AttestationParameters (Valid Input Only) + boolean mAttestationParametersOk = false; + + // Certificate Chain (Structure & Chaining Conditions) + boolean mCertChainOk = false; + + // Binding + boolean mBindingOk = false; + int mBindingType = -1; + + // System Ownership + boolean mSystemOwnershipChecked = false; + boolean mSystemOwned = false; + + // Android Keystore attestation properties + boolean mOsVersionAtLeast10 = false; + boolean mKeyHwBacked = false; + boolean mAttestationVersionAtLeast3 = false; + boolean mKeymasterVersionAtLeast4 = false; + boolean mKeymasterHwBacked = false; + boolean mBootStateIsVerified = false; + boolean mVerifiedBootStateLocked = false; + boolean mOsPatchLevelInRange = false; + boolean mKeyBootPatchLevelInRange = false; + boolean mKeyVendorPatchLevelInRange = false; + + @SuppressLint("WrongConstant") + @Override + public void dumpTo(IndentingPrintWriter writer) { + writer.println( + "Result: " + AttestationVerificationManager.verificationResultCodeToString( + mResult)); + if (!mCertificationFactoryAvailable) { + writer.println("Certificate Factory Unavailable"); + return; + } + if (!mCertPathValidatorAvailable) { + writer.println("Cert Path Validator Unavailable"); + return; + } + if (!mAttestationParametersOk) { + writer.println("Attestation parameters set incorrectly."); + return; + } + + writer.println("Certificate Chain Valid (inc. Trust Anchor): " + booleanToOkFail( + mCertChainOk)); + if (!mCertChainOk) { + return; + } + + // Binding + writer.println("Local Binding: " + booleanToOkFail(mBindingOk)); + writer.increaseIndent(); + writer.println("Binding Type: " + mBindingType); + writer.decreaseIndent(); + + if (mSystemOwnershipChecked) { + writer.println("System Ownership: " + booleanToOkFail(mSystemOwned)); + } + + // Keystore Attestation params + writer.println("KeyStore Attestation Parameters"); + writer.increaseIndent(); + writer.println("OS Version >= 10: " + booleanToOkFail(mOsVersionAtLeast10)); + writer.println("OS Patch Level in Range: " + booleanToOkFail(mOsPatchLevelInRange)); + writer.println( + "Attestation Version >= 3: " + booleanToOkFail(mAttestationVersionAtLeast3)); + writer.println("Keymaster Version >= 4: " + booleanToOkFail(mKeymasterVersionAtLeast4)); + writer.println("Keymaster HW-Backed: " + booleanToOkFail(mKeymasterHwBacked)); + writer.println("Key is HW Backed: " + booleanToOkFail(mKeyHwBacked)); + writer.println("Boot State is VERIFIED: " + booleanToOkFail(mBootStateIsVerified)); + writer.println("Verified Boot is LOCKED: " + booleanToOkFail(mVerifiedBootStateLocked)); + writer.println( + "Key Boot Level in Range: " + booleanToOkFail(mKeyBootPatchLevelInRange)); + writer.println("Key Vendor Patch Level in Range: " + booleanToOkFail( + mKeyVendorPatchLevelInRange)); + writer.decreaseIndent(); + } + + private String booleanToOkFail(boolean value) { + return value ? "OK" : "FAILURE"; + } + } } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 2c67207f407c..4264e912f25a 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -20,9 +20,7 @@ import static android.Manifest.permission.CONTROL_DEVICE_STATE; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.app.StatusBarManager.DISABLE2_GLOBAL_ACTIONS; -import static android.app.StatusBarManager.DISABLE2_MASK; import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE; -import static android.app.StatusBarManager.DISABLE_MASK; import static android.app.StatusBarManager.NAV_BAR_MODE_DEFAULT; import static android.app.StatusBarManager.NAV_BAR_MODE_KIDS; import static android.app.StatusBarManager.NavBarMode; @@ -222,9 +220,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D int what1; int what2; IBinder token; - private String mReason; - DisableRecord(int userId, IBinder token) { + public DisableRecord(int userId, IBinder token) { this.userId = userId; this.token = token; try { @@ -237,12 +234,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public void binderDied() { Slog.i(TAG, "binder died for pkg=" + pkg); - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - disableForUser(info, token, pkg, userId, "Binder Died"); + disableForUser(0, token, pkg, userId); + disable2ForUser(0, token, pkg, userId); token.unlinkToDeath(this, 0); } - public void setFlags(int what, int which, String pkg, String reason) { + public void setFlags(int what, int which, String pkg) { switch (which) { case 1: what1 = what; @@ -256,7 +253,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D break; } this.pkg = pkg; - this.mReason = reason; } public int getFlags(int which) { @@ -275,8 +271,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D @Override public String toString() { - return String.format("userId=%d what1=0x%08X what2=0x%08X pkg=%s token=%s reason=%s", - userId, what1, what2, pkg, token, mReason); + return String.format("userId=%d what1=0x%08X what2=0x%08X pkg=%s token=%s", + userId, what1, what2, pkg, token); } } @@ -954,7 +950,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D if (mBar != null) { try { - mBar.togglePanel(); + mBar.toggleNotificationsPanel(); } catch (RemoteException ex) { } } @@ -1184,59 +1180,57 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D return mTracingEnabled; } - /** - * @deprecated - * Disable some features in the status bar. - * - * This method is deprecated and callers should use - * {@link #disableForUser(StatusBarManager.DisableInfo, IBinder, String, int, String)} - * - * @hide - */ - @Deprecated + // TODO(b/117478341): make it aware of multi-display if needed. @Override public void disable(int what, IBinder token, String pkg) { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(what & DISABLE_MASK, - what & DISABLE2_MASK); - disableForUser(info, token, pkg, mCurrentUserId, null); + disableForUser(what, token, pkg, mCurrentUserId); } + // TODO(b/117478341): make it aware of multi-display if needed. + @Override + public void disableForUser(int what, IBinder token, String pkg, int userId) { + enforceStatusBar(); + + synchronized (mLock) { + disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 1); + } + } + + // TODO(b/117478341): make it aware of multi-display if needed. /** - * @deprecated - * Disable some features in the status bar. - * - * This method is deprecated and callers should use - * {@link #disableForUser(StatusBarManager.DisableInfo, IBinder, String, int, String)} + * Disable additional status bar features. Pass the bitwise-or of the DISABLE2_* flags. + * To re-enable everything, pass {@link #DISABLE2_NONE}. * - * @hide + * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. */ - @Deprecated @Override public void disable2(int what, IBinder token, String pkg) { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(what & DISABLE_MASK, - what & DISABLE2_MASK); - disableForUser(info, token, pkg, mCurrentUserId, null); + disable2ForUser(what, token, pkg, mCurrentUserId); } // TODO(b/117478341): make it aware of multi-display if needed. + /** + * Disable additional status bar features for a given user. Pass the bitwise-or of the + * DISABLE2_* flags. To re-enable everything, pass {@link #DISABLE_NONE}. + * + * Warning: Only pass DISABLE2_* flags into this function, do not use DISABLE_* flags. + */ @Override - public void disableForUser(StatusBarManager.DisableInfo disableInfo, IBinder token, String pkg, - int userId, String reason) { + public void disable2ForUser(int what, IBinder token, String pkg, int userId) { enforceStatusBar(); + synchronized (mLock) { - Pair<Integer, Integer> flags = disableInfo.toFlags(); - disableLocked(DEFAULT_DISPLAY, userId, flags.first, token, pkg, 1, reason); - disableLocked(DEFAULT_DISPLAY, userId, flags.second, token, pkg, 2, reason); + disableLocked(DEFAULT_DISPLAY, userId, what, token, pkg, 2); } } private void disableLocked(int displayId, int userId, int what, IBinder token, String pkg, - int whichFlag, String reason) { + int whichFlag) { // It's important that the the callback and the call to mBar get done // in the same order when multiple threads are calling this function // so they are paired correctly. The messages on the handler will be // handled in the order they were enqueued, but will be outside the lock. - manageDisableListLocked(userId, what, token, pkg, whichFlag, reason); + manageDisableListLocked(userId, what, token, pkg, whichFlag); // Ensure state for the current user is applied, even if passed a non-current user. final int net1 = gatherDisableActionsLocked(mCurrentUserId, 1); @@ -1385,7 +1379,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // also allows calls from window manager which is in this process. enforceStatusBarService(); - final int unknownFlags = flags & ~DISABLE_MASK; + final int unknownFlags = flags & ~StatusBarManager.DISABLE_MASK; if (unknownFlags != 0) { Slog.e(TAG, "Unknown disable flags: 0x" + Integer.toHexString(unknownFlags), new RuntimeException()); @@ -1394,8 +1388,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D if (SPEW) Slog.d(TAG, "setDisableFlags(0x" + Integer.toHexString(flags) + ")"); synchronized (mLock) { - disableLocked(displayId, mCurrentUserId, flags, mSysUiVisToken, cause, 1, - "setDisableFlags"); + disableLocked(displayId, mCurrentUserId, flags, mSysUiVisToken, cause, 1); } } @@ -2450,8 +2443,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // ================================================================================ // lock on mDisableRecords - void manageDisableListLocked(int userId, int what, IBinder token, String pkg, int which, - String reason) { + void manageDisableListLocked(int userId, int what, IBinder token, String pkg, int which) { if (SPEW) { Slog.d(TAG, "manageDisableList userId=" + userId + " what=0x" + Integer.toHexString(what) + " pkg=" + pkg); @@ -2473,7 +2465,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // Update existing record if (record != null) { - record.setFlags(what, which, pkg, reason); + record.setFlags(what, which, pkg); if (record.isEmpty()) { mDisableRecords.remove(i); record.token.unlinkToDeath(record, 0); @@ -2483,7 +2475,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D // Record doesn't exist, so we create a new one record = new DisableRecord(userId, token); - record.setFlags(what, which, pkg, reason); + record.setFlags(what, which, pkg); mDisableRecords.add(record); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java index adb55b41cb48..d6bf02fcdc47 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java +++ b/services/core/java/com/android/server/statusbar/StatusBarShellCommand.java @@ -16,6 +16,8 @@ package com.android.server.statusbar; import static android.app.StatusBarManager.DEFAULT_SETUP_DISABLE2_FLAGS; import static android.app.StatusBarManager.DEFAULT_SETUP_DISABLE_FLAGS; +import static android.app.StatusBarManager.DISABLE2_NONE; +import static android.app.StatusBarManager.DISABLE_NONE; import android.app.StatusBarManager.DisableInfo; import android.content.ComponentName; @@ -25,6 +27,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ShellCommand; import android.service.quicksettings.TileService; +import android.util.Pair; import java.io.PrintWriter; @@ -141,17 +144,25 @@ public class StatusBarShellCommand extends ShellCommand { String arg = getNextArgRequired(); String pkg = mContext.getPackageName(); boolean disable = Boolean.parseBoolean(arg); - int userId = Binder.getCallingUserHandle().getIdentifier(); - DisableInfo info = disable ? new DisableInfo(DEFAULT_SETUP_DISABLE_FLAGS, - DEFAULT_SETUP_DISABLE2_FLAGS) : new DisableInfo(); - mInterface.disableForUser(info, sToken, pkg, userId, "runDisableForSetup"); + + if (disable) { + mInterface.disable(DEFAULT_SETUP_DISABLE_FLAGS, sToken, pkg); + mInterface.disable2(DEFAULT_SETUP_DISABLE2_FLAGS, sToken, pkg); + } else { + mInterface.disable(DISABLE_NONE, sToken, pkg); + mInterface.disable2(DISABLE2_NONE, sToken, pkg); + } + return 0; } private int runSendDisableFlag() { String pkg = mContext.getPackageName(); - int userId = Binder.getCallingUserHandle().getIdentifier(); + int disable1 = DISABLE_NONE; + int disable2 = DISABLE2_NONE; + DisableInfo info = new DisableInfo(); + String arg = getNextArg(); while (arg != null) { switch (arg) { @@ -159,7 +170,7 @@ public class StatusBarShellCommand extends ShellCommand { info.setSearchDisabled(true); break; case "home": - info.setNavigationHomeDisabled(true); + info.setNagivationHomeDisabled(true); break; case "recents": info.setRecentsDisabled(true); @@ -186,7 +197,10 @@ public class StatusBarShellCommand extends ShellCommand { arg = getNextArg(); } - mInterface.disableForUser(info, sToken, pkg, userId, "Shell Commands"); + Pair<Integer, Integer> flagPair = info.toFlags(); + + mInterface.disable(flagPair.first, sToken, pkg); + mInterface.disable2(flagPair.second, sToken, pkg); return 0; } diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java index c74284e5976c..f06d3af49768 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java @@ -1704,6 +1704,15 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks { final Transition transit = task.mTransitionController.requestCloseTransitionIfNeeded(task); if (transit != null) { transit.collectClose(task); + if (!task.mTransitionController.useFullReadyTracking()) { + // If a transition was created here, it means this is an isolated removeTask. It's + // possible for there to be no consequent operations (eg. this is a multiwindow task + // closing so nothing becomes visible in response) so we must "touch" the old ready + // tracker so that it doesn't get stuck. However, since the old ready tracker + // doesn't support multiple conditions, we have to touch it here at the beginning + // before anything that may need it to wait (setReady(false)). + transit.setReady(task, true); + } } else if (task.mTransitionController.isCollecting()) { task.mTransitionController.getCollectingTransition().collectClose(task); } diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java index c9703d871431..0e4f0335118d 100644 --- a/services/core/java/com/android/server/wm/BackNavigationController.java +++ b/services/core/java/com/android/server/wm/BackNavigationController.java @@ -1732,7 +1732,10 @@ class BackNavigationController { // The activity was detached from hierarchy. return; } - activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp(); + + if (activity.mDisplayContent.isFixedRotationLaunchingApp(activity)) { + activity.mDisplayContent.continueUpdateOrientationForDiffOrienLaunchingApp(); + } // Restore the launch-behind state. activity.mTaskSupervisor.scheduleLaunchTaskBehindComplete(activity.token); diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java index 9e16b8abe0de..57827c567b5b 100644 --- a/services/core/java/com/android/server/wm/LetterboxUiController.java +++ b/services/core/java/com/android/server/wm/LetterboxUiController.java @@ -989,6 +989,10 @@ final class LetterboxUiController { } } + boolean isLetterboxEducationEnabled() { + return mLetterboxConfiguration.getIsEducationEnabled(); + } + /** * Whether we use split screen aspect ratio for the activity when camera compat treatment * is active because the corresponding config is enabled and activity supports resizing. diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 6dec71260fa7..72f592b577da 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -64,7 +64,6 @@ import android.os.Environment; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; -import android.os.SystemProperties; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArraySet; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 8bd7b5f78cf4..8defec3dbeab 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3448,6 +3448,8 @@ class Task extends TaskFragment { // Whether the direct top activity is eligible for letterbox education. appCompatTaskInfo.topActivityEligibleForLetterboxEducation = isTopActivityResumed && top.isEligibleForLetterboxEducation(); + appCompatTaskInfo.isLetterboxEducationEnabled = top != null + && top.mLetterboxUiController.isLetterboxEducationEnabled(); // Whether the direct top activity requested showing camera compat control. appCompatTaskInfo.cameraCompatTaskInfo.cameraCompatControlState = isTopActivityResumed ? top.getCameraCompatControlState() diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index dddc7b18d8f6..8fb83fa0e88c 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -1447,14 +1447,17 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP + " last=" + mWindowFrames.mLastFrame + " frame=" + mWindowFrames.mFrame); } + final boolean contentChanged = didFrameInsetsChange || configChanged + || dragResizingChanged || attachedFrameChanged; + // Cancel unchanged non-sync-buffer redraw request to avoid unnecessary reportResized(). + if (!contentChanged && !mRedrawForSyncReported && mPrepareSyncSeqId <= 0 + && mDrawHandlers.isEmpty()) { + mRedrawForSyncReported = true; + } + // Add a window that is using blastSync to the resizing list if it hasn't been reported // already. This because the window is waiting on a finishDrawing from the client. - if (didFrameInsetsChange - || configChanged - || insetsChanged - || dragResizingChanged - || shouldSendRedrawForSync() - || attachedFrameChanged) { + if (contentChanged || insetsChanged || shouldSendRedrawForSync()) { ProtoLog.v(WM_DEBUG_RESIZE, "Resize reasons for w=%s: %s configChanged=%b didFrameInsetsChange=%b", this, mWindowFrames.getInsetsChangedInfo(), diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index a01c1231b373..74ca9ad687ea 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -423,7 +423,7 @@ private: std::set<int32_t> disabledInputDevices{}; // Associated Pointer controller display. - ui::LogicalDisplayId pointerDisplayId{ui::ADISPLAY_ID_DEFAULT}; + ui::LogicalDisplayId pointerDisplayId{ui::LogicalDisplayId::DEFAULT}; // True if stylus button reporting through motion events is enabled. bool stylusButtonMotionEventsEnabled{true}; @@ -1886,7 +1886,7 @@ static jobject nativeCreateInputMonitor(JNIEnv* env, jobject nativeImplObj, jint jstring nameObj, jint pid) { NativeInputManager* im = getNativeInputManager(env, nativeImplObj); - if (displayId == ui::ADISPLAY_ID_NONE.val()) { + if (ui::LogicalDisplayId{displayId} == ui::LogicalDisplayId::INVALID) { std::string message = "InputChannel used as a monitor must be associated with a display"; jniThrowRuntimeException(env, message.c_str()); return nullptr; @@ -2727,6 +2727,11 @@ static void nativeSetInputMethodConnectionIsActive(JNIEnv* env, jobject nativeIm im->setInputMethodConnectionIsActive(isActive); } +static jint nativeGetLastUsedInputDeviceId(JNIEnv* env, jobject nativeImplObj) { + NativeInputManager* im = getNativeInputManager(env, nativeImplObj); + return static_cast<jint>(im->getInputManager()->getReader().getLastUsedInputDeviceId()); +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gInputManagerMethods[] = { @@ -2835,6 +2840,7 @@ static const JNINativeMethod gInputManagerMethods[] = { {"setAccessibilityStickyKeysEnabled", "(Z)V", (void*)nativeSetAccessibilityStickyKeysEnabled}, {"setInputMethodConnectionIsActive", "(Z)V", (void*)nativeSetInputMethodConnectionIsActive}, + {"getLastUsedInputDeviceId", "()I", (void*)nativeGetLastUsedInputDeviceId}, }; #define FIND_CLASS(var, className) \ diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 375fc5a0280a..2b93d2132a8f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -339,6 +339,7 @@ import android.app.admin.ManagedProfileProvisioningParams; import android.app.admin.ManagedSubscriptionsPolicy; import android.app.admin.NetworkEvent; import android.app.admin.PackagePolicy; +import android.app.admin.PackageSetPolicyValue; import android.app.admin.ParcelableGranteeMap; import android.app.admin.ParcelableResource; import android.app.admin.PasswordMetrics; @@ -349,7 +350,6 @@ import android.app.admin.PolicyValue; import android.app.admin.PreferentialNetworkServiceConfig; import android.app.admin.SecurityLog; import android.app.admin.SecurityLog.SecurityEvent; -import android.app.admin.PackageSetPolicyValue; import android.app.admin.StartInstallingUpdateCallback; import android.app.admin.SystemUpdateInfo; import android.app.admin.SystemUpdatePolicy; @@ -2718,6 +2718,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mDevicePolicyEngine.getResolvedPolicy( PolicyDefinition.SECURITY_LOGGING, UserHandle.USER_ALL)); setLoggingConfiguration(securityLoggingEnabled, auditLoggingEnabled); + mInjector.runCryptoSelfTest(); } else { synchronized (getLockObject()) { mSecurityLogMonitor.start(getSecurityLoggingEnabledUser()); @@ -15172,10 +15173,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (statusBarService != null) { int flags1 = disabled ? STATUS_BAR_DISABLE_MASK : StatusBarManager.DISABLE_NONE; int flags2 = disabled ? STATUS_BAR_DISABLE2_MASK : StatusBarManager.DISABLE2_NONE; - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(flags1, - flags2); - statusBarService.disableForUser(info, mToken, mContext.getPackageName(), userId, - "setStatusBarDisabledInternal"); + statusBarService.disableForUser(flags1, mToken, mContext.getPackageName(), userId); + statusBarService.disable2ForUser(flags2, mToken, mContext.getPackageName(), userId); return true; } } catch (RemoteException e) { diff --git a/services/people/java/com/android/server/people/TEST_MAPPING b/services/people/java/com/android/server/people/TEST_MAPPING new file mode 100644 index 000000000000..55b355cbc991 --- /dev/null +++ b/services/people/java/com/android/server/people/TEST_MAPPING @@ -0,0 +1,12 @@ +{ + "presubmit": [ + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.people.data" + } + ] + } + ] +}
\ No newline at end of file diff --git a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt index 9e4f8219ea96..d3072000a56e 100644 --- a/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt +++ b/services/permission/java/com/android/server/permission/access/permission/AppIdPermissionPolicy.kt @@ -1276,7 +1276,23 @@ class AppIdPermissionPolicy : SchemePolicy() { packageName, permissionName ) - else -> permissionAllowlist.getSignatureAppAllowlistState(packageName, permissionName) + else -> + permissionAllowlist.getProductSignatureAppAllowlistState( + packageName, + permissionName + ) + ?: permissionAllowlist.getVendorSignatureAppAllowlistState( + packageName, + permissionName + ) + ?: permissionAllowlist.getSystemExtSignatureAppAllowlistState( + packageName, + permissionName + ) + ?: permissionAllowlist.getSignatureAppAllowlistState( + packageName, + permissionName + ) } } diff --git a/services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionTest.java b/services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionTest.java index 6a82f1656414..3e87c6fe7be7 100644 --- a/services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionTest.java +++ b/services/robotests/backup/src/com/android/server/backup/transport/TransportConnectionTest.java @@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -543,6 +544,18 @@ public class TransportConnectionTest { return future.get(); } + @Test + public void onBindingDied_referenceLost_doesNotThrow() { + TransportConnection.TransportConnectionMonitor transportConnectionMonitor = + new TransportConnection.TransportConnectionMonitor( + mContext, /* transportConnection= */ null); + doThrow(new IllegalArgumentException("Service not registered")).when( + mContext).unbindService(any()); + + // Test no exception is thrown + transportConnectionMonitor.onBindingDied(mTransportComponent); + } + private ServiceConnection verifyBindServiceAsUserAndCaptureServiceConnection(Context context) { ArgumentCaptor<ServiceConnection> connectionCaptor = ArgumentCaptor.forClass(ServiceConnection.class); diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java index 9e11fa2f0bdf..e545a49d3139 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/UserDataPreparerTest.java @@ -71,7 +71,7 @@ public class UserDataPreparerTest { @Mock private Installer mInstaller; - private Object mInstallLock; + private PackageManagerTracedLock mInstallLock; @Before public void setup() { @@ -79,7 +79,7 @@ public class UserDataPreparerTest { TEST_USER.serialNumber = TEST_USER_SERIAL; Context ctx = InstrumentationRegistry.getContext(); FileUtils.deleteContents(ctx.getCacheDir()); - mInstallLock = new Object(); + mInstallLock = new PackageManagerTracedLock(); MockitoAnnotations.initMocks(this); mUserDataPreparer = new TestUserDataPreparer(mInstaller, mInstallLock, mContextMock, ctx.getCacheDir()); @@ -238,8 +238,8 @@ public class UserDataPreparerTest { private static class TestUserDataPreparer extends UserDataPreparer { File testDir; - TestUserDataPreparer(Installer installer, Object installLock, Context context, - File testDir) { + TestUserDataPreparer(Installer installer, PackageManagerTracedLock installLock, + Context context, File testDir) { super(installer, installLock, context); this.testDir = testDir; } diff --git a/services/tests/apexsystemservices/OWNERS b/services/tests/apexsystemservices/OWNERS index 0295b9e99326..8b6675ad22d7 100644 --- a/services/tests/apexsystemservices/OWNERS +++ b/services/tests/apexsystemservices/OWNERS @@ -1,4 +1 @@ -omakoto@google.com -satayev@google.com - include platform/packages/modules/common:/OWNERS diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java index ae6361bdd556..df9671235071 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java @@ -46,6 +46,7 @@ import com.android.server.display.brightness.strategy.AutomaticBrightnessStrateg import com.android.server.display.brightness.strategy.BoostBrightnessStrategy; import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy; import com.android.server.display.brightness.strategy.DozeBrightnessStrategy; +import com.android.server.display.brightness.strategy.FallbackBrightnessStrategy; import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy; import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy; import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy; @@ -90,6 +91,8 @@ public final class DisplayBrightnessStrategySelectorTest { @Mock private AutoBrightnessFallbackStrategy mAutoBrightnessFallbackStrategy; @Mock + private FallbackBrightnessStrategy mFallbackBrightnessStrategy; + @Mock private Resources mResources; @Mock private DisplayManagerFlags mDisplayManagerFlags; @@ -135,7 +138,7 @@ public final class DisplayBrightnessStrategySelectorTest { @Override AutomaticBrightnessStrategy getAutomaticBrightnessStrategy1(Context context, - int displayId) { + int displayId, DisplayManagerFlags displayManagerFlags) { return mAutomaticBrightnessStrategy; } @@ -155,6 +158,11 @@ public final class DisplayBrightnessStrategySelectorTest { AutoBrightnessFallbackStrategy getAutoBrightnessFallbackStrategy() { return mAutoBrightnessFallbackStrategy; } + + @Override + FallbackBrightnessStrategy getFallbackBrightnessStrategy() { + return mFallbackBrightnessStrategy; + } }; @Rule @@ -355,6 +363,25 @@ public final class DisplayBrightnessStrategySelectorTest { } @Test + public void selectStrategy_selectsFallbackStrategyAsAnUltimateFallback() { + when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true); + mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, + mInjector, DISPLAY_ID, mDisplayManagerFlags); + DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock( + DisplayManagerInternal.DisplayPowerRequest.class); + displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; + displayPowerRequest.screenBrightnessOverride = Float.NaN; + when(mFollowerBrightnessStrategy.getBrightnessToFollow()).thenReturn(Float.NaN); + when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN); + when(mAutomaticBrightnessStrategy.shouldUseAutoBrightness()).thenReturn(false); + when(mAutomaticBrightnessStrategy.isAutoBrightnessValid()).thenReturn(false); + assertEquals(mDisplayBrightnessStrategySelector.selectStrategy( + new StrategySelectionRequest(displayPowerRequest, Display.STATE_ON, + 0.1f, false)), + mFallbackBrightnessStrategy); + } + + @Test public void selectStrategyCallsPostProcessorForAllStrategies() { when(mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()).thenReturn(true); mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext, diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java index 3e78118cd5df..19bff56a4b29 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java @@ -18,8 +18,10 @@ package com.android.server.display.brightness.strategy; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -45,6 +47,7 @@ import com.android.server.display.DisplayBrightnessState; import com.android.server.display.brightness.BrightnessEvent; import com.android.server.display.brightness.BrightnessReason; import com.android.server.display.brightness.StrategyExecutionRequest; +import com.android.server.display.feature.DisplayManagerFlags; import org.junit.After; import org.junit.Before; @@ -64,6 +67,9 @@ public class AutomaticBrightnessStrategyTest { @Mock private AutomaticBrightnessController mAutomaticBrightnessController; + @Mock + private DisplayManagerFlags mDisplayManagerFlags; + private BrightnessConfiguration mBrightnessConfiguration; private float mDefaultScreenAutoBrightnessAdjustment; private Context mContext; @@ -80,7 +86,8 @@ public class AutomaticBrightnessStrategyTest { Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, Float.NaN); Settings.System.putFloat(mContext.getContentResolver(), Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.5f); - mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, DISPLAY_ID); + mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, DISPLAY_ID, + mDisplayManagerFlags); mBrightnessConfiguration = new BrightnessConfiguration.Builder( new float[]{0f, 1f}, new float[]{0, PowerManager.BRIGHTNESS_ON}).build(); @@ -247,6 +254,46 @@ public class AutomaticBrightnessStrategyTest { } @Test + public void testAutoBrightnessState_modeSwitch() { + // Setup the test + when(mDisplayManagerFlags.areAutoBrightnessModesEnabled()).thenReturn(true); + mAutomaticBrightnessStrategy.setUseAutoBrightness(true); + boolean allowAutoBrightnessWhileDozing = false; + int brightnessReason = BrightnessReason.REASON_UNKNOWN; + float lastUserSetBrightness = 0.2f; + boolean userSetBrightnessChanged = true; + int policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_BRIGHT; + float pendingBrightnessAdjustment = 0.1f; + Settings.System.putFloat(mContext.getContentResolver(), + Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, pendingBrightnessAdjustment); + mAutomaticBrightnessStrategy.updatePendingAutoBrightnessAdjustments(); + + // Validate no interaction when automaticBrightnessController is in idle mode + when(mAutomaticBrightnessController.isInIdleMode()).thenReturn(true); + mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON, + allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness, + userSetBrightnessChanged); + verify(mAutomaticBrightnessController, never()).switchMode(anyInt()); + + // Validate interaction when automaticBrightnessController is in non-idle mode, and display + // state is ON + when(mAutomaticBrightnessController.isInIdleMode()).thenReturn(false); + mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON, + allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness, + userSetBrightnessChanged); + verify(mAutomaticBrightnessController).switchMode( + AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT); + + // Validate interaction when automaticBrightnessController is in non-idle mode, and display + // state is DOZE + mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_DOZE, + allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness, + userSetBrightnessChanged); + verify(mAutomaticBrightnessController).switchMode( + AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE); + } + + @Test public void accommodateUserBrightnessChangesWorksAsExpected() { // Verify the state if automaticBrightnessController is configured. assertFalse(mAutomaticBrightnessStrategy.isShortTermModelActive()); @@ -390,7 +437,8 @@ public class AutomaticBrightnessStrategyTest { @Test public void testVerifyNoAutoBrightnessAdjustmentsArePopulatedForNonDefaultDisplay() { int newDisplayId = 1; - mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, newDisplayId); + mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy(mContext, newDisplayId, + mDisplayManagerFlags); mAutomaticBrightnessStrategy.putAutoBrightnessAdjustmentSetting(0.3f); assertEquals(0.5f, mAutomaticBrightnessStrategy.getAutoBrightnessAdjustment(), 0.0f); @@ -429,8 +477,7 @@ public class AutomaticBrightnessStrategyTest { updateBrightness_constructsDisplayBrightnessState_withAdjustmentAutoAdjustmentFlag() { BrightnessEvent brightnessEvent = new BrightnessEvent(DISPLAY_ID); mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy( - mContext, DISPLAY_ID, displayId -> brightnessEvent); - new AutomaticBrightnessStrategy(mContext, DISPLAY_ID); + mContext, DISPLAY_ID, displayId -> brightnessEvent, mDisplayManagerFlags); mAutomaticBrightnessStrategy.setAutomaticBrightnessController( mAutomaticBrightnessController); float brightness = 0.4f; @@ -461,8 +508,7 @@ public class AutomaticBrightnessStrategyTest { updateBrightness_constructsDisplayBrightnessState_withAdjustmentTempAdjustmentFlag() { BrightnessEvent brightnessEvent = new BrightnessEvent(DISPLAY_ID); mAutomaticBrightnessStrategy = new AutomaticBrightnessStrategy( - mContext, DISPLAY_ID, displayId -> brightnessEvent); - new AutomaticBrightnessStrategy(mContext, DISPLAY_ID); + mContext, DISPLAY_ID, displayId -> brightnessEvent, mDisplayManagerFlags); mAutomaticBrightnessStrategy.setAutomaticBrightnessController( mAutomaticBrightnessController); float brightness = 0.4f; diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java new file mode 100644 index 000000000000..c4767ae5172b --- /dev/null +++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/FallbackBrightnessStrategyTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.display.brightness.strategy; + + +import static org.junit.Assert.assertEquals; + +import android.hardware.display.DisplayManagerInternal; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.display.DisplayBrightnessState; +import com.android.server.display.brightness.BrightnessReason; +import com.android.server.display.brightness.StrategyExecutionRequest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) + +public class FallbackBrightnessStrategyTest { + private FallbackBrightnessStrategy mFallbackBrightnessStrategy; + + @Before + public void before() { + mFallbackBrightnessStrategy = new FallbackBrightnessStrategy(); + } + + @Test + public void updateBrightness_currentBrightnessIsSet() { + DisplayManagerInternal.DisplayPowerRequest + displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest(); + float currentBrightness = 0.2f; + BrightnessReason brightnessReason = new BrightnessReason(); + brightnessReason.setReason(BrightnessReason.REASON_MANUAL); + DisplayBrightnessState expectedDisplayBrightnessState = + new DisplayBrightnessState.Builder() + .setBrightness(currentBrightness) + .setBrightnessReason(brightnessReason) + .setSdrBrightness(currentBrightness) + .setDisplayBrightnessStrategyName(mFallbackBrightnessStrategy.getName()) + .setShouldUpdateScreenBrightnessSetting(true) + .build(); + DisplayBrightnessState updatedDisplayBrightnessState = + mFallbackBrightnessStrategy.updateBrightness( + new StrategyExecutionRequest(displayPowerRequest, currentBrightness)); + assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState); + } +} diff --git a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java index 88ab871529ee..874e99173c63 100644 --- a/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java +++ b/services/tests/dreamservicetests/src/com/android/server/dreams/DreamControllerTest.java @@ -273,28 +273,36 @@ public class DreamControllerTest { } @Test - public void setDreamHasFocus_true_dreamHasFocus() { + public void setDreamIsObscured_true_dreamIsNotFrontmost() { mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); - mDreamController.setDreamHasFocus(true); - assertTrue(mDreamController.dreamHasFocus()); + mDreamController.setDreamIsObscured(true); + assertFalse(mDreamController.dreamIsFrontmost()); } @Test - public void setDreamHasFocus_false_dreamDoesNotHaveFocus() { + public void setDreamIsObscured_false_dreamIsFrontmost() { mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); - mDreamController.setDreamHasFocus(false); - assertFalse(mDreamController.dreamHasFocus()); + mDreamController.setDreamIsObscured(false); + assertTrue(mDreamController.dreamIsFrontmost()); } @Test - public void setDreamHasFocus_notDreaming_dreamDoesNotHaveFocus() { - mDreamController.setDreamHasFocus(true); - // Dream still doesn't have focus because it was never started. - assertFalse(mDreamController.dreamHasFocus()); + public void setDreamIsObscured_notDreaming_dreamIsNotFrontmost() { + mDreamController.setDreamIsObscured(true); + // Dream still isn't frontmost because it was never started. + assertFalse(mDreamController.dreamIsFrontmost()); + } + + @Test + public void startDream_dreamIsFrontmost() { + mDreamController.startDream(mToken, mDreamName, false /*isPreview*/, false /*doze*/, + 0 /*userId*/, null /*wakeLock*/, mOverlayName, "test" /*reason*/); + + assertTrue(mDreamController.dreamIsFrontmost()); } private ServiceConnection captureServiceConnection() { diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index cc69c1dbf999..28c7fb2396dd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -956,6 +956,7 @@ public class MockingOomAdjusterTests { ConnectionRecord cr = s.getConnections().get(binder).get(0); setFieldValue(ConnectionRecord.class, cr, "activity", mock(ActivityServiceConnectionsHolder.class)); + doReturn(client).when(sService).getTopApp(); doReturn(true).when(cr.activity).isActivityVisible(); sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE); updateOomAdj(client, app); diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt index c9aab5318840..396edae2f672 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt +++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt @@ -186,7 +186,7 @@ class MockSystem(withSession: (StaticMockitoSessionBuilder) -> Unit = {}) { class Mocks { val lock = PackageManagerTracedLock() - val installLock = Any() + val installLock = PackageManagerTracedLock() val injector: PackageManagerServiceInjector = mock() val systemWrapper: PackageManagerServiceInjector.SystemWrapper = mock() val context: Context = mock() 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 7d58a2e53693..79f1574105ba 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java @@ -778,49 +778,6 @@ public final class UserManagerServiceTest { } @Test - public void testGetAliveUsers_shouldExcludeInitialisedEphemeralNonCurrentUsers() { - assertWithMessage("Ephemeral user should not exist at all initially") - .that(mUmi.getUsers(false).stream().anyMatch(u -> u.id == USER_ID)) - .isFalse(); - - // add an ephemeral full user - TestUserData userData = new TestUserData(USER_ID); - userData.info.flags = UserInfo.FLAG_FULL | UserInfo.FLAG_EPHEMERAL; - addUserData(userData); - - assertWithMessage("Ephemeral user should exist as alive after being created") - .that(mUmi.getUsers(true).stream().anyMatch(u -> u.id == USER_ID)) - .isTrue(); - - // mock switch to the user (mark it as initialized & make it the current user) - userData.info.flags |= UserInfo.FLAG_INITIALIZED; - mockCurrentUser(USER_ID); - - assertWithMessage("Ephemeral user should still exist as alive after being switched to") - .that(mUmi.getUsers(true).stream().anyMatch(u -> u.id == USER_ID)) - .isTrue(); - - // switch away from the user - mockCurrentUser(OTHER_USER_ID); - - assertWithMessage("Ephemeral user should not exist as alive after getting switched away") - .that(mUmi.getUsers(true).stream().anyMatch(u -> u.id == USER_ID)) - .isFalse(); - - assertWithMessage("Ephemeral user should still exist as dying after getting switched away") - .that(mUmi.getUsers(false).stream().anyMatch(u -> u.id == USER_ID)) - .isTrue(); - - // finally remove the user - mUms.removeUserInfo(USER_ID); - - assertWithMessage("Ephemeral user should not exist at all after cleanup") - .that(mUmi.getUsers(false).stream().anyMatch(u -> u.id == USER_ID)) - .isFalse(); - } - - - @Test @RequiresFlagsEnabled({android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, Flags.FLAG_BLOCK_PRIVATE_SPACE_CREATION, Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES}) public void testCreatePrivateProfileOnHeadlessSystemUser_shouldAllowCreation() { diff --git a/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java b/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java index 88ca02933450..ec78bcea7539 100644 --- a/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/PinnerServiceTest.java @@ -112,7 +112,7 @@ public class PinnerServiceTest { resources.addOverride( com.android.internal.R.array.config_defaultPinnerServiceFiles, new String[0]); resources.addOverride(com.android.internal.R.bool.config_pinnerCameraApp, false); - resources.addOverride(com.android.internal.R.bool.config_pinnerHomeApp, false); + resources.addOverride(com.android.internal.R.integer.config_pinnerHomePinBytes, 0); resources.addOverride(com.android.internal.R.bool.config_pinnerAssistantApp, false); mFakeDeviceConfigInterface = new FakeDeviceConfigInterface(); @@ -242,7 +242,7 @@ public class PinnerServiceTest { public void testPinHomeApp() throws Exception { // Enable HOME app pinning mContext.getOrCreateTestableResources() - .addOverride(com.android.internal.R.bool.config_pinnerHomeApp, true); + .addOverride(com.android.internal.R.integer.config_pinnerHomePinBytes, 1024); PinnerService pinnerService = new PinnerService(mContext, mInjector); pinnerService.onStart(); @@ -266,7 +266,7 @@ public class PinnerServiceTest { public void testPinHomeAppOnBootCompleted() throws Exception { // Enable HOME app pinning mContext.getOrCreateTestableResources() - .addOverride(com.android.internal.R.bool.config_pinnerHomeApp, true); + .addOverride(com.android.internal.R.integer.config_pinnerHomePinBytes, 1024); PinnerService pinnerService = new PinnerService(mContext, mInjector); pinnerService.onStart(); diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java index 3dc375c5436d..9cd3186f99f3 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthServiceTest.java @@ -368,24 +368,32 @@ public class AuthServiceTest { } @Test - public void testAuthenticate_throwsWhenUsingTestConfigurations() { + public void testAuthenticate_throwsWhenUsingTestApis() { final PromptInfo promptInfo = mock(PromptInfo.class); - when(promptInfo.containsPrivateApiConfigurations()).thenReturn(false); - when(promptInfo.containsTestConfigurations()).thenReturn(true); + when(promptInfo.requiresInternalPermission()).thenReturn(false); + when(promptInfo.requiresTestOrInternalPermission()).thenReturn(true); - testAuthenticate_throwsWhenUsingTestConfigurations(promptInfo); + testAuthenticate_throwsSecurityException(promptInfo); } @Test public void testAuthenticate_throwsWhenUsingPrivateApis() { final PromptInfo promptInfo = mock(PromptInfo.class); - when(promptInfo.containsPrivateApiConfigurations()).thenReturn(true); - when(promptInfo.containsTestConfigurations()).thenReturn(false); + when(promptInfo.requiresInternalPermission()).thenReturn(true); + when(promptInfo.requiresTestOrInternalPermission()).thenReturn(false); - testAuthenticate_throwsWhenUsingTestConfigurations(promptInfo); + testAuthenticate_throwsSecurityException(promptInfo); } - private void testAuthenticate_throwsWhenUsingTestConfigurations(PromptInfo promptInfo) { + @Test + public void testAuthenticate_throwsWhenUsingAdvancedApis() { + final PromptInfo promptInfo = mock(PromptInfo.class); + when(promptInfo.requiresAdvancedPermission()).thenReturn(true); + + testAuthenticate_throwsSecurityException(promptInfo); + } + + private void testAuthenticate_throwsSecurityException(PromptInfo promptInfo) { mAuthService = new AuthService(mContext, mInjector); mAuthService.onStart(); diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index 80fb5e3f950d..1514de04fb08 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -89,6 +89,7 @@ public class KeySyncTaskTest { private static final String WRAPPING_KEY_ALIAS = "KeySyncTaskTest/WrappingKey"; private static final String DATABASE_FILE_NAME = "recoverablekeystore.db"; private static final int TEST_USER_ID = 1000; + private static final int TEST_USER_ID_2 = 1002; private static final int TEST_RECOVERY_AGENT_UID = 10009; private static final int TEST_RECOVERY_AGENT_UID2 = 10010; private static final byte[] TEST_VAULT_HANDLE = @@ -824,6 +825,48 @@ public class KeySyncTaskTest { } @Test + public void run_unlock_keepsRemoteLskfVerificationCounter() throws Exception { + mRecoverableKeyStoreDb.setBadRemoteGuessCounter(TEST_USER_ID, 5); + mRecoverableKeyStoreDb.setBadRemoteGuessCounter(TEST_USER_ID_2, 4); + mKeySyncTask = new KeySyncTask( + mRecoverableKeyStoreDb, + mRecoverySnapshotStorage, + mSnapshotListenersStorage, + TEST_USER_ID, + CREDENTIAL_TYPE_PIN, + "12345".getBytes(), + /*credentialUpdated=*/ false, + mPlatformKeyManager, + mTestOnlyInsecureCertificateHelper, + mMockScrypt); + mKeySyncTask.run(); + + assertThat(mRecoverableKeyStoreDb.getBadRemoteGuessCounter(TEST_USER_ID)).isEqualTo(5); + assertThat(mRecoverableKeyStoreDb.getBadRemoteGuessCounter(TEST_USER_ID_2)).isEqualTo(4); + } + + @Test + public void run_secretChange_resetsRemoteLskfVerificationCounter() throws Exception { + mRecoverableKeyStoreDb.setBadRemoteGuessCounter(TEST_USER_ID, 5); + mRecoverableKeyStoreDb.setBadRemoteGuessCounter(TEST_USER_ID_2, 4); + mKeySyncTask = new KeySyncTask( + mRecoverableKeyStoreDb, + mRecoverySnapshotStorage, + mSnapshotListenersStorage, + TEST_USER_ID, + CREDENTIAL_TYPE_PIN, + "12345".getBytes(), + /*credentialUpdated=*/ true, + mPlatformKeyManager, + mTestOnlyInsecureCertificateHelper, + mMockScrypt); + mKeySyncTask.run(); + + assertThat(mRecoverableKeyStoreDb.getBadRemoteGuessCounter(TEST_USER_ID)).isEqualTo(0); + assertThat(mRecoverableKeyStoreDb.getBadRemoteGuessCounter(TEST_USER_ID_2)).isEqualTo(4); + } + + @Test public void run_customLockScreen_RecoveryStatusFailure() throws Exception { mKeySyncTask = new KeySyncTask( mRecoverableKeyStoreDb, diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java index 9fc46c563841..2f3bca031f46 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java @@ -1786,10 +1786,10 @@ public final class DataManagerTest { /* matchesInterruptionFilter= */ false, /* visibilityOverride= */ 0, /* suppressedVisualEffects= */ 0, - mParentNotificationChannel.getImportance(), + mNotificationChannel.getImportance(), /* explanation= */ null, /* overrideGroupKey= */ null, - mParentNotificationChannel, + mNotificationChannel, /* overridePeople= */ null, /* snoozeCriteria= */ null, /* showBadge= */ true, 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 2d672b89662f..200952c05610 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -112,6 +112,7 @@ import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL; +import static com.android.server.notification.Flags.FLAG_REJECT_OLD_NOTIFICATIONS; import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION; import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; import static com.android.server.notification.NotificationManagerService.NOTIFICATION_TTL; @@ -339,6 +340,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -909,7 +911,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } mService.clearNotifications(); - TestableLooper.get(this).processAllMessages(); + if (mTestableLooper != null) { + mTestableLooper.processAllMessages(); + } try { mService.onDestroy(); @@ -920,14 +924,16 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { InstrumentationRegistry.getInstrumentation() .getUiAutomation().dropShellPermissionIdentity(); - // Remove scheduled messages that would be processed when the test is already done, and - // could cause issues, for example, messages that remove/cancel shown toasts (this causes - // problematic interactions with mocks when they're no longer working as expected). - mWorkerHandler.removeCallbacksAndMessages(null); + if (mWorkerHandler != null) { + // Remove scheduled messages that would be processed when the test is already done, and + // could cause issues, for example, messages that remove/cancel shown toasts (this causes + // problematic interactions with mocks when they're no longer working as expected). + mWorkerHandler.removeCallbacksAndMessages(null); + } - if (TestableLooper.get(this) != null) { + if (mTestableLooper != null) { // Must remove static reference to this test object to prevent leak (b/261039202) - TestableLooper.remove(this); + mTestableLooper.remove(this); } } @@ -1009,7 +1015,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } public void waitForIdle() { - mTestableLooper.processAllMessages(); + if (mTestableLooper != null) { + mTestableLooper.processAllMessages(); + } } private void setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, @@ -1302,6 +1310,106 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { return nrSummary; } + private NotificationRecord createAndPostCallStyleNotification(String packageName, + UserHandle userHandle, String testName) throws Exception { + Person person = new Person.Builder().setName("caller").build(); + Notification.Builder nb = new Notification.Builder(mContext, + mTestNotificationChannel.getId()) + .setFlag(FLAG_USER_INITIATED_JOB, true) + .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) + .setSmallIcon(android.R.drawable.sym_def_app_icon); + StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, 1, + testName, mUid, 0, nb.build(), userHandle, null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mService.addEnqueuedNotification(r); + mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), + r.getUid(), mPostNotificationTrackerFactory.newTracker(null)).run(); + waitForIdle(); + + return mService.findNotificationLocked( + packageName, r.getSbn().getTag(), r.getSbn().getId(), r.getSbn().getUserId()); + } + + private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName) + throws RemoteException { + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, testName, mUid, 0, + nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); + + mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), + nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); + waitForIdle(); + + return mService.findNotificationLocked( + mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); + } + + private static <T extends Parcelable> T parcelAndUnparcel(T source, + Parcelable.Creator<T> creator) { + Parcel parcel = Parcel.obtain(); + source.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + return creator.createFromParcel(parcel); + } + + private PendingIntent createPendingIntent(String action) { + return PendingIntent.getActivity(mContext, 0, + new Intent(action).setPackage(mContext.getPackageName()), + PendingIntent.FLAG_MUTABLE); + } + + private void allowTestPackageToToast() throws Exception { + assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty(); + mService.isSystemUid = false; + mService.isSystemAppId = false; + setToastRateIsWithinQuota(true); + setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false); + // package is not suspended + when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId)) + .thenReturn(false); + } + + private boolean enqueueToast(String testPackage, ITransientNotification callback) + throws RemoteException { + return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(), + callback); + } + + private boolean enqueueToast(INotificationManager service, String testPackage, + IBinder token, ITransientNotification callback) throws RemoteException { + return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */ + true, DEFAULT_DISPLAY); + } + + private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException { + return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY); + } + + private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, + int displayId) throws RemoteException { + return ((INotificationManager) mService.mService).enqueueTextToast(testPackage, + new Binder(), text, TOAST_DURATION, isUiContext, displayId, + /* textCallback= */ null); + } + + private void mockIsVisibleBackgroundUsersSupported(boolean supported) { + when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported); + } + + private void mockIsUserVisible(int displayId, boolean visible) { + when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible); + } + + private void mockDisplayAssignedToUser(int displayId) { + when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId); + } + + private void verifyToastShownForTestPackage(String text, int displayId) { + verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(), + eq(TOAST_DURATION), any(), eq(displayId)); + } + @Test @DisableFlags(FLAG_ALL_NOTIFS_NEED_TTL) public void testLimitTimeOutBroadcast() { @@ -14069,11 +14177,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { public void enqueueUpdate_whenBelowMaxEnqueueRate_accepts() throws Exception { // Post the first version. Notification original = generateNotificationRecord(null).getNotification(); - original.when = 111; + original.when = System.currentTimeMillis(); mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId); waitForIdle(); assertThat(mService.mNotificationList).hasSize(1); - assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(111); + assertThat(mService.mNotificationList.get(0).getNotification().when) + .isEqualTo(original.when); reset(mUsageStats); when(mUsageStats.getAppEnqueueRate(eq(mPkg))) @@ -14081,7 +14190,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Post the update. Notification update = generateNotificationRecord(null).getNotification(); - update.when = 222; + update.when = System.currentTimeMillis() + 111; mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId); waitForIdle(); @@ -14090,18 +14199,19 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mUsageStats, never()).registerPostedByApp(any()); verify(mUsageStats).registerUpdatedByApp(any(), any()); assertThat(mService.mNotificationList).hasSize(1); - assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(222); + assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(update.when); } @Test public void enqueueUpdate_whenAboveMaxEnqueueRate_rejects() throws Exception { // Post the first version. Notification original = generateNotificationRecord(null).getNotification(); - original.when = 111; + original.when = System.currentTimeMillis(); mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId); waitForIdle(); assertThat(mService.mNotificationList).hasSize(1); - assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(111); + assertThat(mService.mNotificationList.get(0).getNotification().when) + .isEqualTo(original.when); reset(mUsageStats); when(mUsageStats.getAppEnqueueRate(eq(mPkg))) @@ -14109,7 +14219,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Post the update. Notification update = generateNotificationRecord(null).getNotification(); - update.when = 222; + update.when = System.currentTimeMillis() + 111; mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId); waitForIdle(); @@ -14118,7 +14228,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mUsageStats, never()).registerPostedByApp(any()); verify(mUsageStats, never()).registerUpdatedByApp(any(), any()); assertThat(mService.mNotificationList).hasSize(1); - assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(111); // old + assertThat(mService.mNotificationList.get(0).getNotification().when) + .isEqualTo(original.when); // old } @Test @@ -15483,103 +15594,48 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertThat(n.getTimeoutAfter()).isEqualTo(20); } - private NotificationRecord createAndPostCallStyleNotification(String packageName, - UserHandle userHandle, String testName) throws Exception { - Person person = new Person.Builder().setName("caller").build(); - Notification.Builder nb = new Notification.Builder(mContext, - mTestNotificationChannel.getId()) - .setFlag(FLAG_USER_INITIATED_JOB, true) - .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) - .setSmallIcon(android.R.drawable.sym_def_app_icon); - StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, 1, - testName, mUid, 0, nb.build(), userHandle, null, 0); + @Test + @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) + public void testRejectOldNotification_oldWhen() throws Exception { + Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setWhen(System.currentTimeMillis() - Duration.ofDays(15).toMillis()) + .build(); + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - mService.addEnqueuedNotification(r); - mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), - r.getUid(), mPostNotificationTrackerFactory.newTracker(null)).run(); - waitForIdle(); - - return mService.findNotificationLocked( - packageName, r.getSbn().getTag(), r.getSbn().getId(), r.getSbn().getUserId()); - } - - private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName) - throws RemoteException { - StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, testName, mUid, 0, - nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); - NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - - mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), - nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); - waitForIdle(); - - return mService.findNotificationLocked( - mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); - } - - private static <T extends Parcelable> T parcelAndUnparcel(T source, - Parcelable.Creator<T> creator) { - Parcel parcel = Parcel.obtain(); - source.writeToParcel(parcel, 0); - parcel.setDataPosition(0); - return creator.createFromParcel(parcel); - } - - private PendingIntent createPendingIntent(String action) { - return PendingIntent.getActivity(mContext, 0, - new Intent(action).setPackage(mContext.getPackageName()), - PendingIntent.FLAG_MUTABLE); - } - - private void allowTestPackageToToast() throws Exception { - assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty(); - mService.isSystemUid = false; - mService.isSystemAppId = false; - setToastRateIsWithinQuota(true); - setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false); - // package is not suspended - when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId)) - .thenReturn(false); - } - - private boolean enqueueToast(String testPackage, ITransientNotification callback) - throws RemoteException { - return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(), - callback); - } - - private boolean enqueueToast(INotificationManager service, String testPackage, - IBinder token, ITransientNotification callback) throws RemoteException { - return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */ - true, DEFAULT_DISPLAY); - } - - private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException { - return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY); - } - - private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, - int displayId) throws RemoteException { - return ((INotificationManager) mService.mService).enqueueTextToast(testPackage, - new Binder(), text, TOAST_DURATION, isUiContext, displayId, - /* textCallback= */ null); + assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) + .isFalse(); } - private void mockIsVisibleBackgroundUsersSupported(boolean supported) { - when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported); - } + @Test + @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) + public void testRejectOldNotification_mediumOldWhen() throws Exception { + Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setWhen(System.currentTimeMillis() - Duration.ofDays(13).toMillis()) + .build(); + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - private void mockIsUserVisible(int displayId, boolean visible) { - when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible); + assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) + .isTrue(); } - private void mockDisplayAssignedToUser(int displayId) { - when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId); - } + @Test + @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) + public void testRejectOldNotification_zeroWhen() throws Exception { + Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) + .setSmallIcon(android.R.drawable.sym_def_app_icon) + .setWhen(0) + .build(); + StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, + n, UserHandle.getUserHandleForUid(mUid), null, 0); + NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - private void verifyToastShownForTestPackage(String text, int displayId) { - verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(), - eq(TOAST_DURATION), any(), eq(displayId)); + assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) + .isTrue(); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java index a60d243c9dad..1195c934a6f7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxUiControllerTest.java @@ -1623,6 +1623,12 @@ public class LetterboxUiControllerTest extends WindowTestsBase { assertTrue(mController.allowHorizontalReachabilityForThinLetterbox()); } + @Test + public void testIsLetterboxEducationEnabled() { + mController.isLetterboxEducationEnabled(); + verify(mLetterboxConfiguration).getIsEducationEnabled(); + } + private void mockThatProperty(String propertyName, boolean value) throws Exception { Property property = new Property(propertyName, /* value */ value, /* packageName */ "", /* className */ ""); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index fbbb9a2e55a7..b152c3e5355f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -819,17 +819,20 @@ public class WindowStateTests extends WindowTestsBase { assertFalse(win.getOrientationChanging()); } - @SetupWindows(addWindows = W_ABOVE_ACTIVITY) @Test public void testRequestResizeForBlastSync() { - final WindowState win = mChildAppWindowAbove; - makeWindowVisible(win, win.getParentWindow()); + final WindowState win = createWindow(null, TYPE_APPLICATION, "window"); + makeWindowVisible(win); + makeLastConfigReportedToClient(win, true /* visible */); win.mLayoutSeq = win.getDisplayContent().mLayoutSeq; win.reportResized(); win.updateResizingWindowIfNeeded(); assertThat(mWm.mResizingWindows).doesNotContain(win); // Check that the window is in resizing if using blast sync. + final BLASTSyncEngine.SyncGroup syncGroup = mock(BLASTSyncEngine.SyncGroup.class); + syncGroup.mSyncMethod = BLASTSyncEngine.METHOD_BLAST; + win.mSyncGroup = syncGroup; win.reportResized(); win.prepareSync(); assertEquals(SYNC_STATE_WAITING_FOR_DRAW, win.mSyncState); @@ -842,6 +845,20 @@ public class WindowStateTests extends WindowTestsBase { mWm.mResizingWindows.remove(win); win.updateResizingWindowIfNeeded(); assertThat(mWm.mResizingWindows).doesNotContain(win); + + // Non blast sync doesn't require to force resizing, because it won't use syncSeqId. + // And if the window is already drawn, it can report sync finish immediately so that the + // sync group won't be blocked. + win.finishSync(mTransaction, syncGroup, false /* cancel */); + syncGroup.mSyncMethod = BLASTSyncEngine.METHOD_NONE; + win.mSyncGroup = syncGroup; + win.mWinAnimator.mDrawState = WindowStateAnimator.HAS_DRAWN; + win.prepareSync(); + assertEquals(SYNC_STATE_WAITING_FOR_DRAW, win.mSyncState); + win.updateResizingWindowIfNeeded(); + assertThat(mWm.mResizingWindows).doesNotContain(win); + assertTrue(win.isSyncFinished(syncGroup)); + assertEquals(WindowContainer.SYNC_STATE_READY, win.mSyncState); } @Test diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 03ba8faa64de..dbe4f2782616 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -13114,39 +13114,41 @@ public class TelephonyManager { }) @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) public @Nullable ServiceState getServiceState(@IncludeLocationData int includeLocationData) { - return getServiceStateForSubscriber(getSubId(), + return getServiceStateForSlot(SubscriptionManager.getSlotIndex(getSubId()), includeLocationData != INCLUDE_LOCATION_DATA_FINE, includeLocationData == INCLUDE_LOCATION_DATA_NONE); } /** - * Returns the service state information on specified subscription. Callers require - * either READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE to retrieve the information. + * Returns the service state information on specified SIM slot. * - * May return {@code null} when the subscription is inactive or when there was an error + * May return {@code null} when the {@code slotIndex} is invalid or when there was an error * communicating with the phone process. + * + * @param slotIndex of phone whose service state is returned * @param renounceFineLocationAccess Set this to true if the caller would not like to receive * location related information which will be sent if the caller already possess * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and do not renounce the permission * @param renounceCoarseLocationAccess Set this to true if the caller would not like to * receive location related information which will be sent if the caller already possess * {@link Manifest.permission#ACCESS_COARSE_LOCATION} and do not renounce the permissions. + * @return Service state on specified SIM slot. */ - private ServiceState getServiceStateForSubscriber(int subId, - boolean renounceFineLocationAccess, + private ServiceState getServiceStateForSlot(int slotIndex, boolean renounceFineLocationAccess, boolean renounceCoarseLocationAccess) { try { ITelephony service = getITelephony(); if (service != null) { - return service.getServiceStateForSubscriber(subId, renounceFineLocationAccess, - renounceCoarseLocationAccess, getOpPackageName(), getAttributionTag()); + return service.getServiceStateForSlot(slotIndex, + renounceFineLocationAccess, renounceCoarseLocationAccess, + getOpPackageName(), getAttributionTag()); } } catch (RemoteException e) { - Log.e(TAG, "Error calling ITelephony#getServiceStateForSubscriber", e); + Log.e(TAG, "Error calling ITelephony#getServiceStateForSlot", e); } catch (NullPointerException e) { AnomalyReporter.reportAnomaly( UUID.fromString("e2bed88e-def9-476e-bd71-3e572a8de6d1"), - "getServiceStateForSubscriber " + subId + " NPE"); + "getServiceStateForSlot " + slotIndex + " NPE"); } return null; } @@ -13161,7 +13163,35 @@ public class TelephonyManager { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) public ServiceState getServiceStateForSubscriber(int subId) { - return getServiceStateForSubscriber(subId, false, false); + return getServiceStateForSlot( + SubscriptionManager.getSlotIndex(subId), false, false); + } + + /** + * Returns the service state information on specified SIM slot. + * + * If you want continuous updates of service state info, register a {@link TelephonyCallback} + * that implements {@link TelephonyCallback.ServiceStateListener} through + * {@link #registerTelephonyCallback}. + * + * May return {@code null} when the {@code slotIndex} is invalid or when there was an error + * communicating with the phone process + * + * See {@link #getActiveModemCount()} to get the total number of slots + * that are active on the device. + * + * @param slotIndex of phone whose service state is returned + * @return ServiceState on specified SIM slot. + * + * @hide + */ + @RequiresPermission(allOf = { + Manifest.permission.READ_PHONE_STATE, + Manifest.permission.ACCESS_COARSE_LOCATION + }) + @RequiresFeature(PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS) + public @Nullable ServiceState getServiceStateForSlot(int slotIndex) { + return getServiceStateForSlot(slotIndex, false, false); } /** diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java index 0bb5fd513fd1..47f53f372d33 100644 --- a/telephony/java/android/telephony/satellite/SatelliteManager.java +++ b/telephony/java/android/telephony/satellite/SatelliteManager.java @@ -1015,13 +1015,27 @@ public final class SatelliteManager { * @hide */ public static final int DATAGRAM_TYPE_KEEP_ALIVE = 3; + /** + * Datagram type indicating that the datagram to be sent or received is of type SOS message and + * is the last message to emergency service provider indicating still needs help. + * @hide + */ + public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP = 4; + /** + * Datagram type indicating that the datagram to be sent or received is of type SOS message and + * is the last message to emergency service provider indicating no more help is needed. + * @hide + */ + public static final int DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED = 5; /** @hide */ @IntDef(prefix = "DATAGRAM_TYPE_", value = { DATAGRAM_TYPE_UNKNOWN, DATAGRAM_TYPE_SOS_MESSAGE, DATAGRAM_TYPE_LOCATION_SHARING, - DATAGRAM_TYPE_KEEP_ALIVE + DATAGRAM_TYPE_KEEP_ALIVE, + DATAGRAM_TYPE_LAST_SOS_MESSAGE_STILL_NEED_HELP, + DATAGRAM_TYPE_LAST_SOS_MESSAGE_NO_HELP_NEEDED }) @Retention(RetentionPolicy.SOURCE) public @interface DatagramType {} diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index d4da7364b07d..65de7e479890 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1399,19 +1399,18 @@ interface ITelephony { oneway void requestModemActivityInfo(in ResultReceiver result); /** - * Get the service state on specified subscription - * @param subId Subscription id + * Get the service state on specified SIM slot. + * @param slotIndex of phone whose service state is returned * @param renounceFineLocationAccess Set this to true if the caller would not like to * receive fine location related information * @param renounceCoarseLocationAccess Set this to true if the caller would not like to * receive coarse location related information * @param callingPackage The package making the call * @param callingFeatureId The feature in the package - * @return Service state on specified subscription. + * @return Service state on specified SIM slot. */ - ServiceState getServiceStateForSubscriber(int subId, boolean renounceFineLocationAccess, - boolean renounceCoarseLocationAccess, - String callingPackage, String callingFeatureId); + ServiceState getServiceStateForSlot(int slotIndex, boolean renounceFineLocationAccess, + boolean renounceCoarseLocationAccess, String callingPackage, String callingFeatureId); /** * Returns the URI for the per-account voicemail ringtone set in Phone settings. diff --git a/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt b/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt index dfbbda6c6f5e..afb3593e3e98 100644 --- a/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt +++ b/tests/AttestationVerificationTest/src/com/android/server/security/AttestationVerificationPeerDeviceVerifierTest.kt @@ -9,21 +9,28 @@ import android.security.attestationverification.AttestationVerificationManager.R import android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS import android.security.attestationverification.AttestationVerificationManager.TYPE_CHALLENGE import android.security.attestationverification.AttestationVerificationManager.TYPE_PUBLIC_KEY +import android.util.IndentingPrintWriter +import android.util.Log import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry +import com.android.server.security.AttestationVerificationManagerService.DumpLogger import com.google.common.truth.Truth.assertThat -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.MockitoAnnotations import java.io.ByteArrayOutputStream +import java.io.PrintWriter +import java.io.StringWriter import java.security.cert.Certificate import java.security.cert.CertificateFactory import java.security.cert.TrustAnchor import java.security.cert.X509Certificate import java.time.LocalDate +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations + /** Test for Peer Device attestation verifier. */ @SmallTest @@ -31,6 +38,7 @@ import java.time.LocalDate class AttestationVerificationPeerDeviceVerifierTest { private val certificateFactory = CertificateFactory.getInstance("X.509") @Mock private lateinit var context: Context + private val dumpLogger = DumpLogger() private lateinit var trustAnchors: HashSet<TrustAnchor> @Before @@ -44,37 +52,50 @@ class AttestationVerificationPeerDeviceVerifierTest { } } + @After + fun dumpAndLog() { + val dump = dumpLogger.getDump() + Log.d(TAG, "$dump") + } + @Test fun verifyAttestation_returnsSuccessTypeChallenge() { val verifier = AttestationVerificationPeerDeviceVerifier( - context, trustAnchors, false, LocalDate.of(2022, 2, 1), - LocalDate.of(2021, 8, 1)) + context, dumpLogger, trustAnchors, false, LocalDate.of(2022, 2, 1), + LocalDate.of(2021, 8, 1) + ) val challengeRequirements = Bundle() challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) - val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, - TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + val result = verifier.verifyAttestation( + TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray() + ) assertThat(result).isEqualTo(RESULT_SUCCESS) } @Test fun verifyAttestation_returnsSuccessLocalPatchOlderThanOneYear() { val verifier = AttestationVerificationPeerDeviceVerifier( - context, trustAnchors, false, LocalDate.of(2022, 2, 1), - LocalDate.of(2021, 1, 1)) + context, dumpLogger, trustAnchors, false, LocalDate.of(2022, 2, 1), + LocalDate.of(2021, 1, 1) + ) val challengeRequirements = Bundle() challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) - val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, - TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + val result = verifier.verifyAttestation( + TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray() + ) assertThat(result).isEqualTo(RESULT_SUCCESS) } @Test fun verifyAttestation_returnsSuccessTypePublicKey() { val verifier = AttestationVerificationPeerDeviceVerifier( - context, trustAnchors, false, LocalDate.of(2022, 2, 1), - LocalDate.of(2021, 8, 1)) + context, dumpLogger, trustAnchors, false, LocalDate.of(2022, 2, 1), + LocalDate.of(2021, 8, 1) + ) val leafCert = (TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToCerts() as List)[0] @@ -84,61 +105,75 @@ class AttestationVerificationPeerDeviceVerifierTest { val result = verifier.verifyAttestation( TYPE_PUBLIC_KEY, pkRequirements, - TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray() + ) assertThat(result).isEqualTo(RESULT_SUCCESS) } @Test fun verifyAttestation_returnsSuccessOwnedBySystem() { val verifier = AttestationVerificationPeerDeviceVerifier( - context, trustAnchors, false, LocalDate.of(2022, 2, 1), - LocalDate.of(2021, 1, 1)) + context, dumpLogger, trustAnchors, false, LocalDate.of(2022, 2, 1), + LocalDate.of(2021, 1, 1) + ) val challengeRequirements = Bundle() challengeRequirements.putByteArray(PARAM_CHALLENGE, "activeUnlockValid".encodeToByteArray()) challengeRequirements.putBoolean("android.key_owned_by_system", true) - val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, - TEST_OWNED_BY_SYSTEM_FILENAME.fromPEMFileToByteArray()) + val result = verifier.verifyAttestation( + TYPE_CHALLENGE, challengeRequirements, + TEST_OWNED_BY_SYSTEM_FILENAME.fromPEMFileToByteArray() + ) + assertThat(result).isEqualTo(RESULT_SUCCESS) } @Test fun verifyAttestation_returnsFailureOwnedBySystem() { val verifier = AttestationVerificationPeerDeviceVerifier( - context, trustAnchors, false, LocalDate.of(2022, 2, 1), - LocalDate.of(2021, 1, 1)) + context, dumpLogger, trustAnchors, false, LocalDate.of(2022, 2, 1), + LocalDate.of(2021, 1, 1) + ) val challengeRequirements = Bundle() challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) challengeRequirements.putBoolean("android.key_owned_by_system", true) - val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, - TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + val result = verifier.verifyAttestation( + TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray() + ) assertThat(result).isEqualTo(RESULT_FAILURE) } @Test fun verifyAttestation_returnsFailurePatchDateNotWithinOneYearLocalPatch() { val verifier = AttestationVerificationPeerDeviceVerifier( - context, trustAnchors, false, LocalDate.of(2023, 3, 1), - LocalDate.of(2023, 2, 1)) + context, dumpLogger, trustAnchors, false, LocalDate.of(2023, 3, 1), + LocalDate.of(2023, 2, 1) + ) val challengeRequirements = Bundle() challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) - val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, - TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + val result = verifier.verifyAttestation( + TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray() + ) assertThat(result).isEqualTo(RESULT_FAILURE) } @Test fun verifyAttestation_returnsFailureTrustedAnchorEmpty() { val verifier = AttestationVerificationPeerDeviceVerifier( - context, HashSet(), false, LocalDate.of(2022, 1, 1), - LocalDate.of(2022, 1, 1)) + context, dumpLogger, HashSet(), false, LocalDate.of(2022, 1, 1), + LocalDate.of(2022, 1, 1) + ) val challengeRequirements = Bundle() challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) - val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, - TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + val result = verifier.verifyAttestation( + TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray() + ) assertThat(result).isEqualTo(RESULT_FAILURE) } @@ -151,32 +186,39 @@ class AttestationVerificationPeerDeviceVerifierTest { } val verifier = AttestationVerificationPeerDeviceVerifier( - context, badTrustAnchors, false, LocalDate.of(2022, 1, 1), - LocalDate.of(2022, 1, 1)) + context, dumpLogger, badTrustAnchors, false, LocalDate.of(2022, 1, 1), + LocalDate.of(2022, 1, 1) + ) val challengeRequirements = Bundle() challengeRequirements.putByteArray(PARAM_CHALLENGE, "player456".encodeToByteArray()) - val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, - TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + val result = verifier.verifyAttestation( + TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray() + ) assertThat(result).isEqualTo(RESULT_FAILURE) } fun verifyAttestation_returnsFailureChallenge() { val verifier = AttestationVerificationPeerDeviceVerifier( - context, trustAnchors, false, LocalDate.of(2022, 1, 1), - LocalDate.of(2022, 1, 1)) + context, dumpLogger, trustAnchors, false, LocalDate.of(2022, 1, 1), + LocalDate.of(2022, 1, 1) + ) val challengeRequirements = Bundle() challengeRequirements.putByteArray(PARAM_CHALLENGE, "wrong".encodeToByteArray()) - val result = verifier.verifyAttestation(TYPE_CHALLENGE, challengeRequirements, - TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray()) + val result = verifier.verifyAttestation( + TYPE_CHALLENGE, challengeRequirements, + TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME.fromPEMFileToByteArray() + ) assertThat(result).isEqualTo(RESULT_FAILURE) } private fun String.fromPEMFileToCerts(): Collection<Certificate> { return certificateFactory.generateCertificates( InstrumentationRegistry.getInstrumentation().getContext().getResources().getAssets() - .open(this)) + .open(this) + ) } private fun String.fromPEMFileToByteArray(): ByteArray { @@ -188,6 +230,12 @@ class AttestationVerificationPeerDeviceVerifierTest { return bos.toByteArray() } + private fun DumpLogger.getDump(): String { + val sw = StringWriter() + this.dumpTo(IndentingPrintWriter(PrintWriter(sw), " ")) + return sw.toString() + } + class TestActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -195,6 +243,7 @@ class AttestationVerificationPeerDeviceVerifierTest { } companion object { + private const val TAG = "AVFTest" private const val TEST_ROOT_CERT_FILENAME = "test_root_certs.pem" private const val TEST_ATTESTATION_WITH_ROOT_CERT_FILENAME = "test_attestation_with_root_certs.pem" diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java index 3ab8d370750f..6bcfebc752f1 100644 --- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java +++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java @@ -176,25 +176,19 @@ public class StatusBarTest extends TestActivity }, new Test("Disable Alerts") { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setNotificationPeekingDisabled(true); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_ALERTS); } }, new Test("Disable Ticker") { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setNotificationTickerDisabled(true); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_TICKER); } }, new Test("Disable Expand in 3 sec.") { public void run() { mHandler.postDelayed(new Runnable() { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setStatusBarExpansionDisabled(true); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND); } }, 3000); } @@ -203,9 +197,7 @@ public class StatusBarTest extends TestActivity public void run() { mHandler.postDelayed(new Runnable() { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setNotificationIconsDisabled(true); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_ICONS); } }, 3000); } @@ -214,73 +206,56 @@ public class StatusBarTest extends TestActivity public void run() { mHandler.postDelayed(new Runnable() { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setStatusBarExpansionDisabled(true); - info.setNotificationIconsDisabled(true); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND + | StatusBarManager.DISABLE_NOTIFICATION_ICONS); } }, 3000); } }, new Test("Disable Home (StatusBarManager)") { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setNavigationHomeDisabled(true); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_HOME); } }, new Test("Disable Back (StatusBarManager)") { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setBackDisabled(true); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_BACK); } }, new Test("Disable Recent (StatusBarManager)") { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setRecentsDisabled(true); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_RECENT); } }, new Test("Disable Clock") { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setClockDisabled(true); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_CLOCK); } }, new Test("Disable System Info") { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setSystemIconsDisabled(true); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_SYSTEM_INFO); } }, new Test("Disable everything in 3 sec") { public void run() { mHandler.postDelayed(new Runnable() { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setDisableAll(); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(~StatusBarManager.DISABLE_NONE); } }, 3000); } }, new Test("Enable everything") { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(StatusBarManager.DISABLE_NONE); } }, new Test("Enable everything in 3 sec.") { public void run() { mHandler.postDelayed(new Runnable() { public void run() { - StatusBarManager.DisableInfo info = new StatusBarManager.DisableInfo(); - info.setEnableAll(); - mStatusBarManager.requestDisabledComponent(info, "test"); + mStatusBarManager.disable(0); } }, 3000); } diff --git a/tests/graphics/SilkFX/AndroidManifest.xml b/tests/graphics/SilkFX/AndroidManifest.xml index c293589bdbaf..25092b52e2b6 100644 --- a/tests/graphics/SilkFX/AndroidManifest.xml +++ b/tests/graphics/SilkFX/AndroidManifest.xml @@ -23,12 +23,13 @@ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application android:label="SilkFX" - android:theme="@android:style/Theme.Material"> + android:theme="@style/Theme.UsefulDefault"> <activity android:name=".Main" android:label="SilkFX Demos" android:banner="@drawable/background1" - android:exported="true"> + android:exported="true" + android:theme="@style/Theme.UsefulDefault"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.DEFAULT"/> diff --git a/tests/graphics/SilkFX/res/values/style.xml b/tests/graphics/SilkFX/res/values/style.xml index 66edbb5c9382..4dd626dfb8f5 100644 --- a/tests/graphics/SilkFX/res/values/style.xml +++ b/tests/graphics/SilkFX/res/values/style.xml @@ -23,9 +23,14 @@ <item name="android:windowElevation">0dp</item> <item name="buttonStyle">@style/AppTheme.Button</item> <item name="colorAccent">#bbffffff</item> + <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> </style> <style name="AppTheme.Button" parent="Widget.AppCompat.Button"> <item name="android:textColor">#ffffffff</item> </style> + <style name="Theme.UsefulDefault" parent="android:Theme.Material"> + <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> + </style> + </resources> diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt index 16785d1d9598..6b360b79c327 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt @@ -25,6 +25,7 @@ class AndroidHeuristicsFilter( val aidlPolicy: FilterPolicyWithReason?, val featureFlagsPolicy: FilterPolicyWithReason?, val syspropsPolicy: FilterPolicyWithReason?, + val rFilePolicy: FilterPolicyWithReason?, fallback: OutputFilter ) : DelegatingFilter(fallback) { override fun getPolicyForClass(className: String): FilterPolicyWithReason { @@ -37,6 +38,9 @@ class AndroidHeuristicsFilter( if (syspropsPolicy != null && classes.isSyspropsClass(className)) { return syspropsPolicy } + if (rFilePolicy != null && classes.isRClass(className)) { + return rFilePolicy + } return super.getPolicyForClass(className) } } @@ -74,3 +78,10 @@ private fun ClassNodes.isSyspropsClass(className: String): Boolean { return className.startsWith("android/sysprop/") && className.endsWith("Properties") } + +/** + * @return if a given class "seems like" an R class or its nested classes. + */ +private fun ClassNodes.isRClass(className: String): Boolean { + return className.endsWith("/R") || className.contains("/R$") +} diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt index 75b5fc8f77ea..c5acd81f1cf2 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt @@ -17,6 +17,7 @@ package com.android.hoststubgen.filters import com.android.hoststubgen.ParseException import com.android.hoststubgen.asm.ClassNodes +import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.log import com.android.hoststubgen.normalizeTextLine import com.android.hoststubgen.whitespaceRegex @@ -31,13 +32,17 @@ import java.util.Objects * Print a class node as a "keep" policy. */ fun printAsTextPolicy(pw: PrintWriter, cn: ClassNode) { - pw.printf("class %s\t%s\n", cn.name, "keep") + pw.printf("class %s %s\n", cn.name.toHumanReadableClassName(), "keep") - for (f in cn.fields ?: emptyList()) { - pw.printf(" field %s\t%s\n", f.name, "keep") + cn.fields?.let { + for (f in it.sortedWith(compareBy({ it.name }))) { + pw.printf(" field %s %s\n", f.name, "keep") + } } - for (m in cn.methods ?: emptyList()) { - pw.printf(" method %s\t%s\t%s\n", m.name, m.desc, "keep") + cn.methods?.let { + for (m in it.sortedWith(compareBy({ it.name }, { it.desc }))) { + pw.printf(" method %s %s %s\n", m.name, m.desc, "keep") + } } } @@ -66,6 +71,7 @@ fun createFilterFromTextPolicyFile( var aidlPolicy: FilterPolicyWithReason? = null var featureFlagsPolicy: FilterPolicyWithReason? = null var syspropsPolicy: FilterPolicyWithReason? = null + var rFilePolicy: FilterPolicyWithReason? = null try { BufferedReader(FileReader(filename)).use { reader -> @@ -162,6 +168,14 @@ fun createFilterFromTextPolicyFile( syspropsPolicy = policy.withReason( "$FILTER_REASON (special-class sysprops)") } + SpecialClass.RFile -> { + if (rFilePolicy != null) { + throw ParseException( + "Policy for R file already defined") + } + rFilePolicy = policy.withReason( + "$FILTER_REASON (special-class R file)") + } } } } @@ -225,13 +239,9 @@ fun createFilterFromTextPolicyFile( throw e.withSourceInfo(filename, lineNo) } - var ret: OutputFilter = imf - if (aidlPolicy != null || featureFlagsPolicy != null || syspropsPolicy != null) { - log.d("AndroidHeuristicsFilter enabled") - ret = AndroidHeuristicsFilter( - classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, imf) - } - return ret + // Wrap the in-memory-filter with AHF. + return AndroidHeuristicsFilter( + classes, aidlPolicy, featureFlagsPolicy, syspropsPolicy, rFilePolicy, imf) } } @@ -240,6 +250,7 @@ private enum class SpecialClass { Aidl, FeatureFlags, Sysprops, + RFile, } private fun resolveSpecialClass(className: String): SpecialClass { @@ -250,6 +261,7 @@ private fun resolveSpecialClass(className: String): SpecialClass { ":aidl" -> return SpecialClass.Aidl ":feature_flags" -> return SpecialClass.FeatureFlags ":sysprops" -> return SpecialClass.Sysprops + ":r" -> return SpecialClass.RFile } throw ParseException("Invalid special class name \"$className\"") } diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt index fa8fe6cd384f..931f0c5fa793 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/01-hoststubgen-test-tiny-framework-orig-dump.txt @@ -322,6 +322,78 @@ NestMembers: InnerClasses: public static #x= #x of #x; // Stub=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub of class com/android/hoststubgen/test/tinyframework/IPretendingAidl public static #x= #x of #x; // Proxy=class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy of class com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub +## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R$Nested + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 3 + public static int[] ARRAY; + descriptor: [I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + + public com.android.hoststubgen.test.tinyframework.R$Nested(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested; + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: iconst_1 + x: newarray int + x: dup + x: iconst_0 + x: iconst_1 + x: iastore + x: putstatic #x // Field ARRAY:[I + x: return + LineNumberTable: +} +SourceFile: "R.java" +NestHost: class com/android/hoststubgen/test/tinyframework/R +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +## Class: com/android/hoststubgen/test/tinyframework/R.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 3 + public com.android.hoststubgen.test.tinyframework.R(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R; +} +SourceFile: "R.java" +NestMembers: + com/android/hoststubgen/test/tinyframework/R$Nested +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class Compiled from "TinyFrameworkCallerCheck.java" class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt index c605f767f527..906a81cf45e3 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/02-hoststubgen-test-tiny-framework-host-stub-dump.txt @@ -122,6 +122,100 @@ RuntimeVisibleAnnotations: NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy +## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R$Nested + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 + public static int[] ARRAY; + descriptor: [I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public com.android.hoststubgen.test.tinyframework.R$Nested(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestHost: class com/android/hoststubgen/test/tinyframework/R +## Class: com/android/hoststubgen/test/tinyframework/R.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 4 + public com.android.hoststubgen.test.tinyframework.R(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestMembers: + com/android/hoststubgen/test/tinyframework/R$Nested ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class Compiled from "TinyFrameworkCallerCheck.java" class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt index 11d5939b7917..10bc91da2544 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/03-hoststubgen-test-tiny-framework-host-impl-dump.txt @@ -348,6 +348,108 @@ RuntimeVisibleAnnotations: NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy +## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R$Nested + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 + public static int[] ARRAY; + descriptor: [I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public com.android.hoststubgen.test.tinyframework.R$Nested(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: iconst_1 + x: newarray int + x: dup + x: iconst_0 + x: iconst_1 + x: iastore + x: putstatic #x // Field ARRAY:[I + x: return + LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestHost: class com/android/hoststubgen/test/tinyframework/R +## Class: com/android/hoststubgen/test/tinyframework/R.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 4 + public com.android.hoststubgen.test.tinyframework.R(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=1, locals=1, args_size=1 + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 0 5 0 this Lcom/android/hoststubgen/test/tinyframework/R; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestMembers: + com/android/hoststubgen/test/tinyframework/R$Nested ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class Compiled from "TinyFrameworkCallerCheck.java" class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt index c605f767f527..906a81cf45e3 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/12-hoststubgen-test-tiny-framework-host-ext-stub-dump.txt @@ -122,6 +122,100 @@ RuntimeVisibleAnnotations: NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy +## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R$Nested + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 + public static int[] ARRAY; + descriptor: [I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public com.android.hoststubgen.test.tinyframework.R$Nested(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=3, locals=0, args_size=0 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestHost: class com/android/hoststubgen/test/tinyframework/R +## Class: com/android/hoststubgen/test/tinyframework/R.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 1, attributes: 4 + public com.android.hoststubgen.test.tinyframework.R(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=3, locals=1, args_size=1 + x: new #x // class java/lang/RuntimeException + x: dup + x: ldc #x // String Stub! + x: invokespecial #x // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V + x: athrow + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestMembers: + com/android/hoststubgen/test/tinyframework/R$Nested ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class Compiled from "TinyFrameworkCallerCheck.java" class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt index 088bc80e11c5..fcf9a8c663ad 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/golden-output/13-hoststubgen-test-tiny-framework-host-ext-impl-dump.txt @@ -481,6 +481,136 @@ RuntimeVisibleAnnotations: NestMembers: com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub com/android/hoststubgen/test/tinyframework/IPretendingAidl$Stub$Proxy +## Class: com/android/hoststubgen/test/tinyframework/R$Nested.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R$Nested + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R$Nested + super_class: #x // java/lang/Object + interfaces: 0, fields: 1, methods: 2, attributes: 4 + public static int[] ARRAY; + descriptor: [I + flags: (0x0009) ACC_PUBLIC, ACC_STATIC + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + public com.android.hoststubgen.test.tinyframework.R$Nested(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/R$Nested; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl + + static {}; + descriptor: ()V + flags: (0x0008) ACC_STATIC + Code: + stack=4, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested + x: ldc #x // String <clinit> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: ldc #x // class com/android/hoststubgen/test/tinyframework/R$Nested + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: iconst_1 + x: newarray int + x: dup + x: iconst_0 + x: iconst_1 + x: iastore + x: putstatic #x // Field ARRAY:[I + x: return + LineNumberTable: + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestHost: class com/android/hoststubgen/test/tinyframework/R +## Class: com/android/hoststubgen/test/tinyframework/R.class + Compiled from "R.java" +public class com.android.hoststubgen.test.tinyframework.R + minor version: 0 + major version: 61 + flags: (0x0021) ACC_PUBLIC, ACC_SUPER + this_class: #x // com/android/hoststubgen/test/tinyframework/R + super_class: #x // java/lang/Object + interfaces: 0, fields: 0, methods: 2, attributes: 4 + private static {}; + descriptor: ()V + flags: (0x000a) ACC_PRIVATE, ACC_STATIC + Code: + stack=2, locals=0, args_size=0 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/R + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.onClassLoaded:(Ljava/lang/Class;Ljava/lang/String;)V + x: return + + public com.android.hoststubgen.test.tinyframework.R(); + descriptor: ()V + flags: (0x0001) ACC_PUBLIC + Code: + stack=4, locals=1, args_size=1 + x: ldc #x // class com/android/hoststubgen/test/tinyframework/R + x: ldc #x // String <init> + x: ldc #x // String ()V + x: ldc #x // String com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall + x: invokestatic #x // Method com/android/hoststubgen/hosthelper/HostTestUtils.callMethodCallHook:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + x: aload_0 + x: invokespecial #x // Method java/lang/Object."<init>":()V + x: return + LineNumberTable: + LocalVariableTable: + Start Length Slot Name Signature + 11 5 0 this Lcom/android/hoststubgen/test/tinyframework/R; + RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +} +InnerClasses: + public static #x= #x of #x; // Nested=class com/android/hoststubgen/test/tinyframework/R$Nested of class com/android/hoststubgen/test/tinyframework/R +SourceFile: "R.java" +RuntimeVisibleAnnotations: + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInStub + x: #x() + com.android.hoststubgen.hosthelper.HostStubGenKeptInImpl +NestMembers: + com/android/hoststubgen/test/tinyframework/R$Nested ## Class: com/android/hoststubgen/test/tinyframework/TinyFrameworkCallerCheck$Impl.class Compiled from "TinyFrameworkCallerCheck.java" class com.android.hoststubgen.test.tinyframework.TinyFrameworkCallerCheck$Impl diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt index d30208452a40..696b6d009dc2 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/policy-override-tiny-framework.txt @@ -19,6 +19,9 @@ class com/android/hoststubgen/test/tinyframework/TinyFrameworkForTextPolicy ~com # Heuristics rule: Stub all the AIDL classes. class :aidl stubclass +# Heuristics rule: Stub all the R classes. +class :r stubclass + # Default is "remove", so let's put all the base classes / interfaces in the stub first. class com.android.hoststubgen.test.tinyframework.subclasstest.C1 stub class com.android.hoststubgen.test.tinyframework.subclasstest.C2 stub diff --git a/core/java/android/app/StatusBarManager.aidl b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java index 687678c4ea8d..b1bedf4b6853 100644 --- a/core/java/android/app/StatusBarManager.aidl +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-framework/src/com/android/hoststubgen/test/tinyframework/R.java @@ -1,11 +1,11 @@ -/** - * Copyright (c) 2024, The Android Open Source Project +/* + * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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, @@ -13,7 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package com.android.hoststubgen.test.tinyframework; -package android.app; - -parcelable StatusBarManager.DisableInfo;
\ No newline at end of file +public class R { + public static class Nested { + public static int[] ARRAY = new int[] {1}; + } +} diff --git a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java index 762180dcf74b..37925e82bdb6 100644 --- a/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java +++ b/tools/hoststubgen/hoststubgen/test-tiny-framework/tiny-test/src/com/android/hoststubgen/test/tinyframework/TinyFrameworkClassTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; +import com.android.hoststubgen.test.tinyframework.R.Nested; import com.android.hoststubgen.test.tinyframework.TinyFrameworkNestedClasses.SubClass; import org.junit.Rule; @@ -328,4 +329,9 @@ public class TinyFrameworkClassTest { assertThat(IPretendingAidl.Stub.addOne(1)).isEqualTo(2); assertThat(IPretendingAidl.Stub.Proxy.addTwo(1)).isEqualTo(3); } + + @Test + public void testRFileHeuristics() { + assertThat(Nested.ARRAY.length).isEqualTo(1); + } } |