diff options
759 files changed, 29859 insertions, 9133 deletions
diff --git a/Android.bp b/Android.bp index 48f0928f24d7..54cb2684068d 100644 --- a/Android.bp +++ b/Android.bp @@ -107,7 +107,6 @@ filegroup { ":android.hardware.radio.data-V3-java-source", ":android.hardware.radio.network-V3-java-source", ":android.hardware.radio.voice-V3-java-source", - ":android.hardware.security.keymint-V3-java-source", ":android.hardware.security.secureclock-V1-java-source", ":android.hardware.thermal-V3-java-source", ":android.hardware.tv.tuner-V3-java-source", @@ -116,7 +115,6 @@ filegroup { ":android.security.legacykeystore-java-source", ":android.security.maintenance-java-source", ":android.security.metrics-java-source", - ":android.system.keystore2-V4-java-source", ":android.hardware.cas-V1-java-source", ":credstore_aidl", ":dumpstate_aidl", @@ -149,7 +147,16 @@ filegroup { ":statslog-framework-java-gen", // FrameworkStatsLog.java ":statslog-hwui-java-gen", // HwuiStatsLog.java ":audio_policy_configuration_V7_0", - ], + ] + select(release_flag("RELEASE_ATTEST_MODULES"), { + true: [ + ":android.hardware.security.keymint-V4-java-source", + ":android.system.keystore2-V5-java-source", + ], + default: [ + ":android.hardware.security.keymint-V3-java-source", + ":android.system.keystore2-V4-java-source", + ], + }), } java_library { @@ -398,6 +405,7 @@ java_defaults { "bouncycastle-repackaged-unbundled", "com.android.sysprop.foldlockbehavior", "com.android.sysprop.view", + "configinfra_framework_flags_java_lib", "framework-internal-utils", "dynamic_instrumentation_manager_aidl-java", // If MimeMap ever becomes its own APEX, then this dependency would need to be removed diff --git a/FF_LEADS_OWNERS b/FF_LEADS_OWNERS new file mode 100644 index 000000000000..a650c6b7a26f --- /dev/null +++ b/FF_LEADS_OWNERS @@ -0,0 +1,10 @@ +bills@google.com +carmenjackson@google.com +nalini@google.com +nosh@google.com +olilan@google.com +philipcuadra@google.com +rajekumar@google.com +shayba@google.com +timmurray@google.com +zezeozue@google.com diff --git a/apex/jobscheduler/service/aconfig/alarm.aconfig b/apex/jobscheduler/service/aconfig/alarm.aconfig index d3068d7d37e8..a6e980726a9a 100644 --- a/apex/jobscheduler/service/aconfig/alarm.aconfig +++ b/apex/jobscheduler/service/aconfig/alarm.aconfig @@ -2,16 +2,6 @@ package: "com.android.server.alarm" container: "system" flag { - name: "use_frozen_state_to_drop_listener_alarms" - namespace: "backstage_power" - description: "Use frozen state callback to drop listener alarms for cached apps" - bug: "324470945" - metadata { - purpose: PURPOSE_BUGFIX - } -} - -flag { name: "start_user_before_scheduled_alarms" namespace: "multiuser" description: "Persist list of users with alarms scheduled and wakeup stopped users before alarms are due" diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index 033da2df9bf6..60ba3b896a28 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -282,7 +282,6 @@ public class AlarmManagerService extends SystemService { private final Injector mInjector; int mBroadcastRefCount = 0; - boolean mUseFrozenStateToDropListenerAlarms; MetricsHelper mMetricsHelper; PowerManager.WakeLock mWakeLock; SparseIntArray mAlarmsPerUid = new SparseIntArray(); @@ -1784,40 +1783,37 @@ public class AlarmManagerService extends SystemService { mMetricsHelper = new MetricsHelper(getContext(), mLock); mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); - mUseFrozenStateToDropListenerAlarms = Flags.useFrozenStateToDropListenerAlarms(); mStartUserBeforeScheduledAlarms = Flags.startUserBeforeScheduledAlarms() && UserManager.supportsMultipleUsers(); if (mStartUserBeforeScheduledAlarms) { mUserWakeupStore = new UserWakeupStore(); mUserWakeupStore.init(); } - if (mUseFrozenStateToDropListenerAlarms) { - final ActivityManager.UidFrozenStateChangedCallback callback = (uids, frozenStates) -> { - final int size = frozenStates.length; - if (uids.length != size) { - Slog.wtf(TAG, "Got different length arrays in frozen state callback!" - + " uids.length: " + uids.length + " frozenStates.length: " + size); - // Cannot process received data in any meaningful way. - return; - } - final IntArray affectedUids = new IntArray(); - for (int i = 0; i < size; i++) { - if (frozenStates[i] != UID_FROZEN_STATE_FROZEN) { - continue; - } - if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, - uids[i])) { - continue; - } - affectedUids.add(uids[i]); + final ActivityManager.UidFrozenStateChangedCallback callback = (uids, frozenStates) -> { + final int size = frozenStates.length; + if (uids.length != size) { + Slog.wtf(TAG, "Got different length arrays in frozen state callback!" + + " uids.length: " + uids.length + " frozenStates.length: " + size); + // Cannot process received data in any meaningful way. + return; + } + final IntArray affectedUids = new IntArray(); + for (int i = 0; i < size; i++) { + if (frozenStates[i] != UID_FROZEN_STATE_FROZEN) { + continue; } - if (affectedUids.size() > 0) { - removeExactListenerAlarms(affectedUids.toArray()); + if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, + uids[i])) { + continue; } - }; - final ActivityManager am = getContext().getSystemService(ActivityManager.class); - am.registerUidFrozenStateChangedCallback(new HandlerExecutor(mHandler), callback); - } + affectedUids.add(uids[i]); + } + if (affectedUids.size() > 0) { + removeExactListenerAlarms(affectedUids.toArray()); + } + }; + final ActivityManager am = getContext().getSystemService(ActivityManager.class); + am.registerUidFrozenStateChangedCallback(new HandlerExecutor(mHandler), callback); mListenerDeathRecipient = new IBinder.DeathRecipient() { @Override @@ -2994,13 +2990,10 @@ public class AlarmManagerService extends SystemService { pw.println("Feature Flags:"); pw.increaseIndent(); - pw.print(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS, - mUseFrozenStateToDropListenerAlarms); - pw.println(); pw.print(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS, Flags.startUserBeforeScheduledAlarms()); - pw.decreaseIndent(); pw.println(); + pw.decreaseIndent(); pw.println(); pw.println("App Standby Parole: " + mAppStandbyParole); @@ -5146,38 +5139,6 @@ public class AlarmManagerService extends SystemService { removeForStoppedLocked(uid); } } - - @Override - public void handleUidCachedChanged(int uid, boolean cached) { - if (mUseFrozenStateToDropListenerAlarms) { - // Use ActivityManager#UidFrozenStateChangedCallback instead. - return; - } - if (!CompatChanges.isChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, uid)) { - return; - } - // Apps can quickly get frozen after being cached, breaking the exactness guarantee on - // listener alarms. So going forward, the contract of exact listener alarms explicitly - // states that they will be removed as soon as the app goes out of lifecycle. We still - // allow a short grace period for quick shuffling of proc-states that may happen - // unexpectedly when switching between different lifecycles and is generally hard for - // apps to avoid. - - final long delay; - synchronized (mLock) { - delay = mConstants.CACHED_LISTENER_REMOVAL_DELAY; - } - final Integer uidObj = uid; - - if (cached && !mHandler.hasEqualMessages(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, - uidObj)) { - mHandler.sendMessageDelayed( - mHandler.obtainMessage(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj), - delay); - } else { - mHandler.removeEqualMessages(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED, uidObj); - } - } }; private final BroadcastStats getStatsLocked(PendingIntent pi) { diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp index 1ebe0cdfabd7..89351fd47ff8 100644 --- a/api/ApiDocs.bp +++ b/api/ApiDocs.bp @@ -61,6 +61,7 @@ stubs_defaults { ":framework-bluetooth-sources", ":framework-connectivity-tiramisu-updatable-sources", ":framework-graphics-srcs", + ":framework-healthfitness-sources", ":framework-mediaprovider-sources", ":framework-nearby-sources", ":framework-nfc-updatable-sources", diff --git a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java index f726361effd6..a88796c38166 100644 --- a/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java +++ b/cmds/uiautomator/library/core-src/com/android/uiautomator/core/AccessibilityNodeInfoDumper.java @@ -217,6 +217,9 @@ public class AccessibilityNodeInfoDumper { serializer.attribute("", "selected", Boolean.toString(node.isSelected())); serializer.attribute("", "bounds", AccessibilityNodeInfoHelper.getVisibleBoundsInScreen( node, width, height).toShortString()); + serializer.attribute("", "drawing-order", Integer.toString(node.getDrawingOrder())); + serializer.attribute("", "hint", safeCharSeqToString(node.getHintText())); + int count = node.getChildCount(); for (int i = 0; i < count; i++) { AccessibilityNodeInfo child = node.getChild(i); diff --git a/core/api/current.txt b/core/api/current.txt index 06cf9a5631ee..cda3f95950f7 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -23,6 +23,7 @@ package android { field public static final String ACTIVITY_RECOGNITION = "android.permission.ACTIVITY_RECOGNITION"; field public static final String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL"; field public static final String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS"; + field @FlaggedApi("android.media.tv.flags.apply_picture_profiles") public static final String APPLY_PICTURE_PROFILE = "android.permission.APPLY_PICTURE_PROFILE"; field public static final String BATTERY_STATS = "android.permission.BATTERY_STATS"; field public static final String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE"; field public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET"; @@ -336,7 +337,7 @@ package android { field public static final String WRITE_SECURE_SETTINGS = "android.permission.WRITE_SECURE_SETTINGS"; field public static final String WRITE_SETTINGS = "android.permission.WRITE_SETTINGS"; field public static final String WRITE_SYNC_SETTINGS = "android.permission.WRITE_SYNC_SETTINGS"; - field @FlaggedApi("com.android.settingslib.flags.settings_catalyst") public static final String WRITE_SYSTEM_PREFERENCES = "android.permission.WRITE_SYSTEM_PREFERENCES"; + field @FlaggedApi("com.android.settingslib.flags.write_system_preference_permission_enabled") public static final String WRITE_SYSTEM_PREFERENCES = "android.permission.WRITE_SYSTEM_PREFERENCES"; field public static final String WRITE_VOICEMAIL = "com.android.voicemail.permission.WRITE_VOICEMAIL"; } @@ -1276,6 +1277,7 @@ package android { field public static final int paddingStart = 16843699; // 0x10103b3 field public static final int paddingTop = 16842967; // 0x10100d7 field public static final int paddingVertical = 16844094; // 0x101053e + field @FlaggedApi("android.content.pm.app_compat_option_16kb") public static final int pageSizeCompat; field public static final int panelBackground = 16842846; // 0x101005e field public static final int panelColorBackground = 16842849; // 0x1010061 field public static final int panelColorForeground = 16842848; // 0x1010060 @@ -2043,6 +2045,12 @@ package android { field public static final int system_error_container_light = 17170554; // 0x106007a field public static final int system_error_dark = 17170595; // 0x10600a3 field public static final int system_error_light = 17170552; // 0x1060078 + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_on_surface_dark; + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_on_surface_light; + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_primary_dark; + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_primary_light; + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_surface_dark; + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_inverse_surface_light; field public static final int system_neutral1_0 = 17170461; // 0x106001d field public static final int system_neutral1_10 = 17170462; // 0x106001e field public static final int system_neutral1_100 = 17170464; // 0x1060020 @@ -2119,12 +2127,16 @@ package android { field public static final int system_primary_fixed = 17170612; // 0x10600b4 field public static final int system_primary_fixed_dim = 17170613; // 0x10600b5 field public static final int system_primary_light = 17170528; // 0x1060060 + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_scrim_dark; + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_scrim_light; field public static final int system_secondary_container_dark = 17170573; // 0x106008d field public static final int system_secondary_container_light = 17170530; // 0x1060062 field public static final int system_secondary_dark = 17170575; // 0x106008f field public static final int system_secondary_fixed = 17170616; // 0x10600b8 field public static final int system_secondary_fixed_dim = 17170617; // 0x10600b9 field public static final int system_secondary_light = 17170532; // 0x1060064 + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_shadow_dark; + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_shadow_light; field public static final int system_surface_bright_dark = 17170590; // 0x106009e field public static final int system_surface_bright_light = 17170547; // 0x1060073 field public static final int system_surface_container_dark = 17170587; // 0x106009b @@ -2142,6 +2154,8 @@ package android { field public static final int system_surface_dim_light = 17170548; // 0x1060074 field public static final int system_surface_disabled = 17170626; // 0x10600c2 field public static final int system_surface_light = 17170540; // 0x106006c + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_surface_tint_dark; + field @FlaggedApi("android.os.material_colors_10_2024") public static final int system_surface_tint_light; field public static final int system_surface_variant_dark = 17170592; // 0x10600a0 field public static final int system_surface_variant_light = 17170549; // 0x1060075 field public static final int system_tertiary_container_dark = 17170577; // 0x1060091 @@ -6221,6 +6235,7 @@ package android.app { } public class KeyguardManager { + method @FlaggedApi("android.app.device_unlock_listener") @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void addDeviceLockedStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.KeyguardManager.DeviceLockedStateListener); method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void addKeyguardLockedStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.KeyguardManager.KeyguardLockedStateListener); method @Deprecated public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence); method @Deprecated @RequiresPermission(android.Manifest.permission.DISABLE_KEYGUARD) public void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult); @@ -6230,10 +6245,15 @@ package android.app { method public boolean isKeyguardLocked(); method public boolean isKeyguardSecure(); method @Deprecated public android.app.KeyguardManager.KeyguardLock newKeyguardLock(String); + method @FlaggedApi("android.app.device_unlock_listener") @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void removeDeviceLockedStateListener(@NonNull android.app.KeyguardManager.DeviceLockedStateListener); method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void removeKeyguardLockedStateListener(@NonNull android.app.KeyguardManager.KeyguardLockedStateListener); method public void requestDismissKeyguard(@NonNull android.app.Activity, @Nullable android.app.KeyguardManager.KeyguardDismissCallback); } + @FlaggedApi("android.app.device_unlock_listener") @java.lang.FunctionalInterface public static interface KeyguardManager.DeviceLockedStateListener { + method public void onDeviceLockedStateChanged(boolean); + } + public abstract static class KeyguardManager.KeyguardDismissCallback { ctor public KeyguardManager.KeyguardDismissCallback(); method public void onDismissCancelled(); @@ -13567,6 +13587,7 @@ package android.content.pm { field public static final String PROPERTY_MEDIA_CAPABILITIES = "android.media.PROPERTY_MEDIA_CAPABILITIES"; field public static final String PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES = "android.net.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES"; field public static final String PROPERTY_SPECIAL_USE_FGS_SUBTYPE = "android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"; + field @FlaggedApi("com.android.server.backup.enable_restricted_mode_changes") public static final String PROPERTY_USE_RESTRICTED_BACKUP_MODE = "android.app.backup.PROPERTY_USE_RESTRICTED_BACKUP_MODE"; field public static final int SIGNATURE_FIRST_NOT_SIGNED = -1; // 0xffffffff field public static final int SIGNATURE_MATCH = 0; // 0x0 field public static final int SIGNATURE_NEITHER_SIGNED = 1; // 0x1 @@ -13803,6 +13824,7 @@ package android.content.pm { public final class SharedLibraryInfo implements android.os.Parcelable { method public int describeContents(); + method @FlaggedApi("android.content.pm.sdk_dependency_installer") @NonNull public java.util.List<java.lang.String> getCertDigests(); method @NonNull public android.content.pm.VersionedPackage getDeclaringPackage(); method @NonNull public java.util.List<android.content.pm.VersionedPackage> getDependentPackages(); method @IntRange(from=0xffffffff) public long getLongVersion(); @@ -17470,6 +17492,7 @@ package android.graphics { method public void setFloatUniform(@NonNull String, @NonNull float[]); method public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter); method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader); + method public void setInputXfermode(@NonNull String, @NonNull android.graphics.RuntimeXfermode); method public void setIntUniform(@NonNull String, int); method public void setIntUniform(@NonNull String, int, int); method public void setIntUniform(@NonNull String, int, int, int); @@ -17488,7 +17511,29 @@ package android.graphics { method public void setFloatUniform(@NonNull String, float, float, float, float); method public void setFloatUniform(@NonNull String, @NonNull float[]); method public void setInputBuffer(@NonNull String, @NonNull android.graphics.BitmapShader); + method @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter); method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader); + method @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public void setInputXfermode(@NonNull String, @NonNull android.graphics.RuntimeXfermode); + method public void setIntUniform(@NonNull String, int); + method public void setIntUniform(@NonNull String, int, int); + method public void setIntUniform(@NonNull String, int, int, int); + method public void setIntUniform(@NonNull String, int, int, int, int); + method public void setIntUniform(@NonNull String, @NonNull int[]); + } + + @FlaggedApi("com.android.graphics.hwui.flags.runtime_color_filters_blenders") public class RuntimeXfermode extends android.graphics.Xfermode { + ctor public RuntimeXfermode(@NonNull String); + method public void setColorUniform(@NonNull String, @ColorInt int); + method public void setColorUniform(@NonNull String, @ColorLong long); + method public void setColorUniform(@NonNull String, @NonNull android.graphics.Color); + method public void setFloatUniform(@NonNull String, float); + method public void setFloatUniform(@NonNull String, float, float); + method public void setFloatUniform(@NonNull String, float, float, float); + method public void setFloatUniform(@NonNull String, float, float, float, float); + method public void setFloatUniform(@NonNull String, @NonNull float[]); + method public void setInputColorFilter(@NonNull String, @NonNull android.graphics.ColorFilter); + method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader); + method public void setInputXfermode(@NonNull String, @NonNull android.graphics.RuntimeXfermode); method public void setIntUniform(@NonNull String, int); method public void setIntUniform(@NonNull String, int, int); method public void setIntUniform(@NonNull String, int, int, int); @@ -18826,6 +18871,19 @@ package android.hardware { field public static final int TRANSFER_UNSPECIFIED = 0; // 0x0 } + @FlaggedApi("android.hardware.flags.luts_api") public final class DisplayLuts { + ctor @FlaggedApi("android.hardware.flags.luts_api") public DisplayLuts(); + method @FlaggedApi("android.hardware.flags.luts_api") public void set(@NonNull android.hardware.DisplayLuts.Entry); + method @FlaggedApi("android.hardware.flags.luts_api") public void set(@NonNull android.hardware.DisplayLuts.Entry, @NonNull android.hardware.DisplayLuts.Entry); + } + + @FlaggedApi("android.hardware.flags.luts_api") public static class DisplayLuts.Entry { + ctor @FlaggedApi("android.hardware.flags.luts_api") public DisplayLuts.Entry(@NonNull float[], int, int); + method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public float[] getBuffer(); + method @FlaggedApi("android.hardware.flags.luts_api") public int getDimension(); + method @FlaggedApi("android.hardware.flags.luts_api") public int getSamplingKey(); + } + public class GeomagneticField { ctor public GeomagneticField(float, float, float, long); method public float getDeclination(); @@ -18887,8 +18945,19 @@ package android.hardware { field @FlaggedApi("android.media.codec.p210_format_support") public static final int YCBCR_P210 = 60; // 0x3c } + @FlaggedApi("android.hardware.flags.luts_api") public final class LutProperties { + method @FlaggedApi("android.hardware.flags.luts_api") public int getDimension(); + method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public int[] getSamplingKeys(); + method @FlaggedApi("android.hardware.flags.luts_api") public int getSize(); + field @FlaggedApi("android.hardware.flags.luts_api") public static final int ONE_DIMENSION = 1; // 0x1 + field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_MAX_RGB = 1; // 0x1 + field @FlaggedApi("android.hardware.flags.luts_api") public static final int SAMPLING_KEY_RGB = 0; // 0x0 + field @FlaggedApi("android.hardware.flags.luts_api") public static final int THREE_DIMENSION = 3; // 0x3 + } + @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public final class OverlayProperties implements android.os.Parcelable { method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public int describeContents(); + method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public android.hardware.LutProperties[] getLutProperties(); method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public boolean isCombinationSupported(int, int); method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public boolean isMixedColorSpacesSupported(); method @FlaggedApi("android.hardware.flags.overlayproperties_class_api") public void writeToParcel(@NonNull android.os.Parcel, int); @@ -21494,6 +21563,7 @@ package android.media { method public int getId(); method public CharSequence getProductName(); method @NonNull public int[] getSampleRates(); + method @FlaggedApi("android.media.audio.speaker_layout_api") public int getSpeakerLayoutChannelMask(); method public int getType(); method public boolean isSink(); method public boolean isSource(); @@ -21982,7 +22052,7 @@ package android.media { public final class AudioPlaybackConfiguration implements android.os.Parcelable { method public int describeContents(); method public android.media.AudioAttributes getAudioAttributes(); - method @Nullable public android.media.AudioDeviceInfo getAudioDeviceInfo(); + method @Deprecated @FlaggedApi("android.media.audio.routed_device_ids") @Nullable public android.media.AudioDeviceInfo getAudioDeviceInfo(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioPlaybackConfiguration> CREATOR; } @@ -22065,6 +22135,7 @@ package android.media { method public android.media.AudioDeviceInfo getPreferredDevice(); method public int getRecordingState(); method public android.media.AudioDeviceInfo getRoutedDevice(); + method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices(); method public int getSampleRate(); method public int getState(); method public int getTimestamp(@NonNull android.media.AudioTimestamp, int); @@ -22159,6 +22230,7 @@ package android.media { method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); + method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public default java.util.List<android.media.AudioDeviceInfo> getRoutedDevices(); method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener); method public boolean setPreferredDevice(android.media.AudioDeviceInfo); } @@ -22217,6 +22289,7 @@ package android.media { method public int getPositionNotificationPeriod(); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); + method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices(); method public int getSampleRate(); method @IntRange(from=1) public int getStartThresholdInFrames(); method public int getState(); @@ -24385,6 +24458,7 @@ package android.media { method @NonNull public android.media.PlaybackParams getPlaybackParams(); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); + method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; method @NonNull public android.media.SyncParams getSyncParams(); method @Nullable public android.media.MediaTimestamp getTimestamp(); @@ -24598,6 +24672,7 @@ package android.media { method public android.os.PersistableBundle getMetrics(); method public android.media.AudioDeviceInfo getPreferredDevice(); method public android.media.AudioDeviceInfo getRoutedDevice(); + method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull public java.util.List<android.media.AudioDeviceInfo> getRoutedDevices(); method public android.view.Surface getSurface(); method public boolean isPrivacySensitive(); method public void pause() throws java.lang.IllegalStateException; @@ -26980,6 +27055,83 @@ package android.media.projection { } +package android.media.quality { + + @FlaggedApi("android.media.tv.flags.media_quality_fw") public class MediaQualityContract { + } + + public static final class MediaQualityContract.PictureQuality { + field public static final String PARAMETER_BRIGHTNESS = "brightness"; + field public static final String PARAMETER_CONTRAST = "contrast"; + field public static final String PARAMETER_SATURATION = "saturation"; + field public static final String PARAMETER_SHARPNESS = "sharpness"; + } + + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager { + method @NonNull public java.util.List<android.media.quality.PictureProfile> getAvailablePictureProfiles(); + method @NonNull public java.util.List<android.media.quality.ParamCapability> getParamCapabilities(@NonNull java.util.List<java.lang.String>); + method @Nullable public android.media.quality.PictureProfile getPictureProfile(int, @NonNull String); + method public void registerPictureProfileCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.quality.MediaQualityManager.PictureProfileCallback); + method public void removePictureProfile(@NonNull String); + method public void unregisterPictureProfileCallback(@NonNull android.media.quality.MediaQualityManager.PictureProfileCallback); + method public void updatePictureProfile(@NonNull String, @NonNull android.media.quality.PictureProfile); + } + + public abstract static class MediaQualityManager.PictureProfileCallback { + ctor public MediaQualityManager.PictureProfileCallback(); + method public void onError(int); + method public void onParamCapabilitiesChanged(@Nullable String, @NonNull java.util.List<android.media.quality.ParamCapability>); + method public void onPictureProfileAdded(@NonNull String, @NonNull android.media.quality.PictureProfile); + method public void onPictureProfileRemoved(@NonNull String, @NonNull android.media.quality.PictureProfile); + method public void onPictureProfileUpdated(@NonNull String, @NonNull android.media.quality.PictureProfile); + } + + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class ParamCapability implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.os.Bundle getCapabilities(); + method @NonNull public String getParamName(); + method public int getParamType(); + method public boolean isSupported(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final String CAPABILITY_DEFAULT = "default"; + field public static final String CAPABILITY_ENUM = "enum"; + field public static final String CAPABILITY_MAX = "max"; + field public static final String CAPABILITY_MIN = "min"; + field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.ParamCapability> CREATOR; + field public static final int TYPE_DOUBLE = 3; // 0x3 + field public static final int TYPE_INT = 1; // 0x1 + field public static final int TYPE_LONG = 2; // 0x2 + field public static final int TYPE_STRING = 4; // 0x4 + } + + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class PictureProfile implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public String getInputId(); + method @NonNull public String getName(); + method @Nullable public String getPackageName(); + method @NonNull public android.os.PersistableBundle getParameters(); + method @Nullable public String getProfileId(); + method public int getProfileType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.media.quality.PictureProfile> CREATOR; + field public static final int ERROR_DUPLICATE = 2; // 0x2 + field public static final int ERROR_INVALID_ARGUMENT = 3; // 0x3 + field public static final int ERROR_NOT_ALLOWLISTED = 4; // 0x4 + field public static final int ERROR_NO_PERMISSION = 1; // 0x1 + field public static final int ERROR_UNKNOWN = 0; // 0x0 + field public static final int TYPE_APPLICATION = 2; // 0x2 + field public static final int TYPE_SYSTEM = 1; // 0x1 + } + + public static final class PictureProfile.Builder { + ctor public PictureProfile.Builder(@NonNull String); + ctor public PictureProfile.Builder(@NonNull android.media.quality.PictureProfile); + method @NonNull public android.media.quality.PictureProfile build(); + method @NonNull public android.media.quality.PictureProfile.Builder setParameters(@NonNull android.os.PersistableBundle); + } + +} + package android.media.session { public final class MediaController { @@ -28529,6 +28681,8 @@ package android.media.tv.ad { method public void setCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.ad.TvAdView.TvAdCallback); method public void setOnUnhandledInputEventListener(@NonNull android.media.tv.ad.TvAdView.OnUnhandledInputEventListener); method public boolean setTvView(@Nullable android.media.tv.TvView); + method @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public void setZOrderMediaOverlay(boolean); + method @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") public void setZOrderOnTop(boolean); method public void startAdService(); method public void stopAdService(); field public static final String ERROR_KEY_ERROR_CODE = "error_code"; @@ -28801,6 +28955,8 @@ package android.media.tv.interactive { method public void setOnUnhandledInputEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.interactive.TvInteractiveAppView.OnUnhandledInputEventListener); method public void setTeletextAppEnabled(boolean); method public int setTvView(@Nullable android.media.tv.TvView); + method @FlaggedApi("android.media.tv.flags.tiaf_v_apis") public void setZOrderMediaOverlay(boolean); + method @FlaggedApi("android.media.tv.flags.tiaf_v_apis") public void setZOrderOnTop(boolean); method public void startInteractiveApp(); method public void stopInteractiveApp(); field public static final String BI_INTERACTIVE_APP_KEY_ALIAS = "alias"; @@ -29840,6 +29996,7 @@ package android.net.vcn { method @NonNull public java.util.List<android.net.vcn.VcnUnderlyingNetworkTemplate> getVcnUnderlyingNetworkPriorities(); method public boolean hasGatewayOption(int); method @FlaggedApi("android.net.vcn.safe_mode_config") public boolean isSafeModeEnabled(); + field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; // 0xffffffff field public static final int VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY = 0; // 0x0 } @@ -33313,6 +33470,14 @@ package android.os { method public final android.os.CountDownTimer start(); } + @FlaggedApi("android.os.cpu_gpu_headrooms") public final class CpuHeadroomParams { + ctor public CpuHeadroomParams(); + method public int getCalculationType(); + method public void setCalculationType(int); + field public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1 + field public static final int CPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0 + } + public final class CpuUsageInfo implements android.os.Parcelable { method public int describeContents(); method public long getActive(); @@ -33560,6 +33725,14 @@ package android.os { method public void onProgress(long); } + @FlaggedApi("android.os.cpu_gpu_headrooms") public final class GpuHeadroomParams { + ctor public GpuHeadroomParams(); + method public int getCalculationType(); + method public void setCalculationType(int); + field public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; // 0x1 + field public static final int GPU_HEADROOM_CALCULATION_TYPE_MIN = 0; // 0x0 + } + public class Handler { ctor @Deprecated public Handler(); ctor @Deprecated public Handler(@Nullable android.os.Handler.Callback); @@ -34660,8 +34833,6 @@ package android.os { method public static android.os.VibrationEffect createWaveform(long[], int[], int); method public int describeContents(); method @NonNull public static android.os.VibrationEffect.Composition startComposition(); - method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public static android.os.VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope(); - method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public static android.os.VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope(@FloatRange(from=0) float); field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationEffect> CREATOR; field public static final int DEFAULT_AMPLITUDE = -1; // 0xffffffff field public static final int EFFECT_CLICK = 0; // 0x0 @@ -34689,8 +34860,10 @@ package android.os { } @FlaggedApi("android.os.vibrator.normalized_pwle_effects") public static final class VibrationEffect.WaveformEnvelopeBuilder { + ctor public VibrationEffect.WaveformEnvelopeBuilder(); method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.WaveformEnvelopeBuilder addControlPoint(@FloatRange(from=0, to=1) float, @FloatRange(from=0) float, int); method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect build(); + method @FlaggedApi("android.os.vibrator.normalized_pwle_effects") @NonNull public android.os.VibrationEffect.WaveformEnvelopeBuilder setInitialFrequencyHz(@FloatRange(from=0) float); } public abstract class Vibrator { @@ -34810,6 +34983,10 @@ package android.os.health { } public class SystemHealthManager { + method @FlaggedApi("android.os.cpu_gpu_headrooms") @FloatRange(from=0.0f, to=100.0f) public float getCpuHeadroom(@Nullable android.os.CpuHeadroomParams); + method @FlaggedApi("android.os.cpu_gpu_headrooms") public long getCpuHeadroomMinIntervalMillis(); + method @FlaggedApi("android.os.cpu_gpu_headrooms") @FloatRange(from=0.0f, to=100.0f) public float getGpuHeadroom(@Nullable android.os.GpuHeadroomParams); + method @FlaggedApi("android.os.cpu_gpu_headrooms") public long getGpuHeadroomMinIntervalMillis(); method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getPowerMonitorReadings(@NonNull java.util.List<android.os.PowerMonitor>, @Nullable java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.os.PowerMonitorReadings,java.lang.RuntimeException>); method @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public void getSupportedPowerMonitors(@Nullable java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.util.List<android.os.PowerMonitor>>); method public android.os.health.HealthStats takeMyUidSnapshot(); @@ -40681,6 +40858,7 @@ package android.service.autofill { method public int describeContents(); method @Deprecated @Nullable public android.os.Bundle getClientState(); method @Nullable public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents(); + method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getSessionId(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.service.autofill.FillEventHistory> CREATOR; } @@ -40690,10 +40868,12 @@ package android.service.autofill { method @Nullable public android.os.Bundle getClientState(); method @Nullable public String getDatasetId(); method @NonNull public java.util.Map<android.view.autofill.AutofillId,android.service.autofill.FieldClassification> getFieldsClassification(); + method @FlaggedApi("android.service.autofill.autofill_w_metrics") @Nullable public android.view.autofill.AutofillId getFocusedId(); method @NonNull public java.util.Set<java.lang.String> getIgnoredDatasetIds(); method @NonNull public java.util.Map<android.view.autofill.AutofillId,java.util.Set<java.lang.String>> getManuallyEnteredField(); method public int getNoSaveUiReason(); method @NonNull public java.util.Set<java.lang.String> getSelectedDatasetIds(); + method @FlaggedApi("android.service.autofill.autofill_w_metrics") @NonNull public java.util.Set<java.lang.String> getShownDatasetIds(); method public int getType(); method public int getUiType(); field public static final int NO_SAVE_UI_REASON_DATASET_MATCH = 6; // 0x6 @@ -40702,6 +40882,7 @@ package android.service.autofill { field public static final int NO_SAVE_UI_REASON_NONE = 0; // 0x0 field public static final int NO_SAVE_UI_REASON_NO_SAVE_INFO = 1; // 0x1 field public static final int NO_SAVE_UI_REASON_NO_VALUE_CHANGED = 4; // 0x4 + field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final int NO_SAVE_UI_REASON_USING_CREDMAN = 7; // 0x7 field public static final int NO_SAVE_UI_REASON_WITH_DELAY_SAVE_FLAG = 2; // 0x2 field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2 field public static final int TYPE_CONTEXT_COMMITTED = 4; // 0x4 @@ -40710,6 +40891,7 @@ package android.service.autofill { field public static final int TYPE_DATASET_SELECTED = 0; // 0x0 field public static final int TYPE_SAVE_SHOWN = 3; // 0x3 field public static final int TYPE_VIEW_REQUESTED_AUTOFILL = 6; // 0x6 + field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final int UI_TYPE_CREDMAN = 4; // 0x4 field public static final int UI_TYPE_DIALOG = 3; // 0x3 field public static final int UI_TYPE_INLINE = 2; // 0x2 field public static final int UI_TYPE_MENU = 1; // 0x1 @@ -41995,6 +42177,7 @@ package android.service.quickaccesswallet { public abstract class QuickAccessWalletService extends android.app.Service { ctor public QuickAccessWalletService(); + method @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") @Nullable public android.app.PendingIntent getGestureTargetActivityPendingIntent(); method @Nullable public android.app.PendingIntent getTargetActivityPendingIntent(); method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent); method public abstract void onWalletCardSelected(@NonNull android.service.quickaccesswallet.SelectWalletCardRequest); @@ -46672,6 +46855,8 @@ package android.telephony { method public long getDataUsageBytes(); method public long getDataUsageTime(); method @NonNull public int[] getNetworkTypes(); + method @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") @Nullable public java.time.ZonedDateTime getPlanEndDate(); + method @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public int getSubscriptionStatus(); method @Nullable public CharSequence getSummary(); method @Nullable public CharSequence getTitle(); method public void writeToParcel(android.os.Parcel, int); @@ -46682,6 +46867,11 @@ package android.telephony { field public static final int LIMIT_BEHAVIOR_DISABLED = 0; // 0x0 field public static final int LIMIT_BEHAVIOR_THROTTLED = 2; // 0x2 field public static final int LIMIT_BEHAVIOR_UNKNOWN = -1; // 0xffffffff + field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_ACTIVE = 1; // 0x1 + field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_INACTIVE = 2; // 0x2 + field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_SUSPENDED = 4; // 0x4 + field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_TRIAL = 3; // 0x3 + field @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") public static final int SUBSCRIPTION_STATUS_UNKNOWN = 0; // 0x0 field public static final long TIME_UNKNOWN = -1L; // 0xffffffffffffffffL } @@ -46693,6 +46883,7 @@ package android.telephony { method public android.telephony.SubscriptionPlan.Builder setDataLimit(long, int); method public android.telephony.SubscriptionPlan.Builder setDataUsage(long, long); method @NonNull public android.telephony.SubscriptionPlan.Builder setNetworkTypes(@NonNull int[]); + method @FlaggedApi("com.android.internal.telephony.flags.subscription_plan_allow_status_and_end_date") @NonNull public android.telephony.SubscriptionPlan.Builder setSubscriptionStatus(int); method public android.telephony.SubscriptionPlan.Builder setSummary(@Nullable CharSequence); method public android.telephony.SubscriptionPlan.Builder setTitle(@Nullable CharSequence); } @@ -49672,6 +49863,14 @@ package android.text.style { method public abstract void updateMeasureState(@NonNull android.text.TextPaint); } + @FlaggedApi("android.view.inputmethod.writing_tools") public final class NoWritingToolsSpan implements android.text.ParcelableSpan { + ctor public NoWritingToolsSpan(); + method public int describeContents(); + method public int getSpanTypeId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.text.style.NoWritingToolsSpan> CREATOR; + } + public interface ParagraphStyle { } @@ -53168,6 +53367,7 @@ package android.view { method @FlaggedApi("com.android.window.flags.sdk_desired_present_time") @NonNull public android.view.SurfaceControl.Transaction setFrameTimeline(long); method @Deprecated @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int); method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int); + method @FlaggedApi("android.hardware.flags.luts_api") @NonNull public android.view.SurfaceControl.Transaction setLuts(@NonNull android.view.SurfaceControl, @Nullable android.hardware.DisplayLuts); method @NonNull public android.view.SurfaceControl.Transaction setOpaque(@NonNull android.view.SurfaceControl, boolean); method @NonNull public android.view.SurfaceControl.Transaction setPosition(@NonNull android.view.SurfaceControl, float, float); method @NonNull public android.view.SurfaceControl.Transaction setScale(@NonNull android.view.SurfaceControl, float, float); @@ -54842,6 +55042,8 @@ package android.view { method public abstract void setTransformation(android.graphics.Matrix); method public abstract void setVisibility(int); method public abstract void setWebDomain(@Nullable String); + field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE"; + field @FlaggedApi("android.service.autofill.autofill_w_metrics") public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER"; } public abstract static class ViewStructure.HtmlInfo { @@ -56564,6 +56766,11 @@ package android.view.autofill { public final class AutofillId implements android.os.Parcelable { method @NonNull public static android.view.autofill.AutofillId create(@NonNull android.view.View, int); method public int describeContents(); + method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getAutofillVirtualId(); + method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getSessionId(); + method @FlaggedApi("android.service.autofill.autofill_w_metrics") public int getViewId(); + method @FlaggedApi("android.service.autofill.autofill_w_metrics") public boolean isInAutofillSession(); + method @FlaggedApi("android.service.autofill.autofill_w_metrics") public boolean isVirtual(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.view.autofill.AutofillId> CREATOR; } @@ -56960,6 +57167,7 @@ package android.view.inputmethod { method @NonNull public java.util.Set<java.lang.Class<? extends android.view.inputmethod.PreviewableHandwritingGesture>> getSupportedHandwritingGesturePreviews(); method @NonNull public java.util.List<java.lang.Class<? extends android.view.inputmethod.HandwritingGesture>> getSupportedHandwritingGestures(); method @FlaggedApi("android.view.inputmethod.editorinfo_handwriting_enabled") public boolean isStylusHandwritingEnabled(); + method @FlaggedApi("android.view.inputmethod.writing_tools") public boolean isWritingToolsEnabled(); method public final void makeCompatible(int); method @FlaggedApi("android.view.inputmethod.public_autofill_id_in_editorinfo") public void setAutofillId(@Nullable android.view.autofill.AutofillId); method public void setInitialSurroundingSubText(@NonNull CharSequence, int); @@ -56968,6 +57176,7 @@ package android.view.inputmethod { method @FlaggedApi("android.view.inputmethod.editorinfo_handwriting_enabled") public void setStylusHandwritingEnabled(boolean); method public void setSupportedHandwritingGesturePreviews(@NonNull java.util.Set<java.lang.Class<? extends android.view.inputmethod.PreviewableHandwritingGesture>>); method public void setSupportedHandwritingGestures(@NonNull java.util.List<java.lang.Class<? extends android.view.inputmethod.HandwritingGesture>>); + method @FlaggedApi("android.view.inputmethod.writing_tools") public void setWritingToolsEnabled(boolean); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.EditorInfo> CREATOR; field public static final int IME_ACTION_DONE = 6; // 0x6 diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt index 4ada53e1bf34..ad5bd31828e0 100644 --- a/core/api/lint-baseline.txt +++ b/core/api/lint-baseline.txt @@ -1,4 +1,10 @@ // Baseline format: 1.0 +ActionValue: android.view.ViewStructure#EXTRA_VIRTUAL_STRUCTURE_TYPE: + Inconsistent extra value; expected `android.view.extra.VIRTUAL_STRUCTURE_TYPE`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE` +ActionValue: android.view.ViewStructure#EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER: + Inconsistent extra value; expected `android.view.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER` + + BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED: Field 'ACTION_NEXT_ALARM_CLOCK_CHANGED' is missing @BroadcastBehavior BroadcastBehavior: android.app.AlarmManager#ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED: @@ -1185,6 +1191,10 @@ UnflaggedApi: android.R.dimen#system_corner_radius_xlarge: New API must be flagged with @FlaggedApi: field android.R.dimen.system_corner_radius_xlarge UnflaggedApi: android.R.dimen#system_corner_radius_xsmall: New API must be flagged with @FlaggedApi: field android.R.dimen.system_corner_radius_xsmall +UnflaggedApi: android.R.integer#status_bar_notification_info_maxnum: + Changes from not deprecated to deprecated must be flagged with @FlaggedApi: field android.R.integer.status_bar_notification_info_maxnum +UnflaggedApi: android.R.string#status_bar_notification_info_overflow: + Changes from not deprecated to deprecated must be flagged with @FlaggedApi: field android.R.string.status_bar_notification_info_overflow UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INTERNAL_ERROR: New API must be flagged with @FlaggedApi: field android.accessibilityservice.AccessibilityService.OVERLAY_RESULT_INTERNAL_ERROR UnflaggedApi: android.accessibilityservice.AccessibilityService#OVERLAY_RESULT_INVALID: @@ -1477,7 +1487,6 @@ UnflaggedApi: android.graphics.text.PositionedGlyphs#getItalicOverride(int): New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getItalicOverride(int) UnflaggedApi: android.graphics.text.PositionedGlyphs#getWeightOverride(int): New API must be flagged with @FlaggedApi: method android.graphics.text.PositionedGlyphs.getWeightOverride(int) - UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_CAR: New API must be flagged with @FlaggedApi: field android.media.MediaRoute2Info.TYPE_REMOTE_CAR UnflaggedApi: android.media.MediaRoute2Info#TYPE_REMOTE_COMPUTER: diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index bc73220cb4c1..1a949d84c052 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -251,6 +251,10 @@ package android.media.session { package android.net { + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class ConnectivityFrameworkInitializerBaklava { + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static void registerServiceWrappers(); + } + public class LocalSocket implements java.io.Closeable { ctor public LocalSocket(@NonNull java.io.FileDescriptor); } @@ -310,6 +314,25 @@ package android.net.netstats { } +package android.net.vcn { + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public final class VcnTransportInfo implements android.os.Parcelable android.net.TransportInfo { + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int describeContents(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public long getApplicableRedactions(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public int getMinUdpPort4500NatTimeoutSeconds(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.TransportInfo makeCopy(long); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public void writeToParcel(@NonNull android.os.Parcel, int); + field @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public static final android.os.Parcelable.Creator<android.net.vcn.VcnTransportInfo> CREATOR; + } + + @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public static final class VcnTransportInfo.Builder { + ctor @FlaggedApi("android.net.vcn.mainline_vcn_module_api") public VcnTransportInfo.Builder(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo build(); + method @FlaggedApi("android.net.vcn.mainline_vcn_module_api") @NonNull public android.net.vcn.VcnTransportInfo.Builder setMinUdpPort4500NatTimeoutSeconds(@IntRange(from=0x78) int); + } + +} + package android.net.wifi { public final class WifiMigration { @@ -379,6 +402,13 @@ package android.os { field public static final int DEVICE_INITIAL_SDK_INT; } + public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable { + method @FlaggedApi("android.os.enable_has_binders") public int hasBinders(); + field @FlaggedApi("android.os.enable_has_binders") public static final int STATUS_BINDERS_NOT_PRESENT = 0; // 0x0 + field @FlaggedApi("android.os.enable_has_binders") public static final int STATUS_BINDERS_PRESENT = 1; // 0x1 + field @FlaggedApi("android.os.enable_has_binders") public static final int STATUS_BINDERS_UNKNOWN = 2; // 0x2 + } + public class Handler { method @FlaggedApi("android.os.mainline_vcn_platform_api") public final boolean hasMessagesOrCallbacks(); method @FlaggedApi("android.os.mainline_vcn_platform_api") public final void removeCallbacksAndEqualMessages(@Nullable Object); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index ed95fdd52f45..b2bd2d5ded85 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -57,6 +57,7 @@ package android { field @Deprecated public static final String BIND_CONNECTION_SERVICE = "android.permission.BIND_CONNECTION_SERVICE"; field public static final String BIND_CONTENT_CAPTURE_SERVICE = "android.permission.BIND_CONTENT_CAPTURE_SERVICE"; field public static final String BIND_CONTENT_SUGGESTIONS_SERVICE = "android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE"; + field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final String BIND_DEPENDENCY_INSTALLER = "android.permission.BIND_DEPENDENCY_INSTALLER"; field public static final String BIND_DIRECTORY_SEARCH = "android.permission.BIND_DIRECTORY_SEARCH"; field public static final String BIND_DISPLAY_HASHING_SERVICE = "android.permission.BIND_DISPLAY_HASHING_SERVICE"; field @FlaggedApi("com.android.internal.telephony.flags.use_oem_domain_selection_service") public static final String BIND_DOMAIN_SELECTION_SERVICE = "android.permission.BIND_DOMAIN_SELECTION_SERVICE"; @@ -65,6 +66,7 @@ package android { field @FlaggedApi("android.crashrecovery.flags.enable_crashrecovery") public static final String BIND_EXPLICIT_HEALTH_CHECK_SERVICE = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE"; field public static final String BIND_EXTERNAL_STORAGE_SERVICE = "android.permission.BIND_EXTERNAL_STORAGE_SERVICE"; field public static final String BIND_FIELD_CLASSIFICATION_SERVICE = "android.permission.BIND_FIELD_CLASSIFICATION_SERVICE"; + field @FlaggedApi("android.security.afl_api") public static final String BIND_FORENSIC_EVENT_TRANSPORT_SERVICE = "android.permission.BIND_FORENSIC_EVENT_TRANSPORT_SERVICE"; field public static final String BIND_GBA_SERVICE = "android.permission.BIND_GBA_SERVICE"; field public static final String BIND_HOTWORD_DETECTION_SERVICE = "android.permission.BIND_HOTWORD_DETECTION_SERVICE"; field public static final String BIND_IMS_SERVICE = "android.permission.BIND_IMS_SERVICE"; @@ -164,6 +166,7 @@ package android { field public static final String HDMI_CEC = "android.permission.HDMI_CEC"; field @Deprecated public static final String HIDE_NON_SYSTEM_OVERLAY_WINDOWS = "android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"; field public static final String INJECT_EVENTS = "android.permission.INJECT_EVENTS"; + field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final String INSTALL_DEPENDENCY_SHARED_LIBRARIES = "android.permission.INSTALL_DEPENDENCY_SHARED_LIBRARIES"; field public static final String INSTALL_DPC_PACKAGES = "android.permission.INSTALL_DPC_PACKAGES"; field public static final String INSTALL_DYNAMIC_SYSTEM = "android.permission.INSTALL_DYNAMIC_SYSTEM"; field public static final String INSTALL_EXISTING_PACKAGES = "com.android.permission.INSTALL_EXISTING_PACKAGES"; @@ -209,6 +212,7 @@ package android { field @FlaggedApi("android.permission.flags.enhanced_confirmation_mode_apis_enabled") public static final String MANAGE_ENHANCED_CONFIRMATION_STATES = "android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES"; field public static final String MANAGE_ETHERNET_NETWORKS = "android.permission.MANAGE_ETHERNET_NETWORKS"; field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION"; + field @FlaggedApi("android.security.afl_api") public static final String MANAGE_FORENSIC_STATE = "android.permission.MANAGE_FORENSIC_STATE"; field public static final String MANAGE_GAME_ACTIVITY = "android.permission.MANAGE_GAME_ACTIVITY"; field public static final String MANAGE_GAME_MODE = "android.permission.MANAGE_GAME_MODE"; field @FlaggedApi("android.media.tv.flags.media_quality_fw") public static final String MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE = "android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE"; @@ -304,6 +308,7 @@ package android { field public static final String READ_CONTENT_RATING_SYSTEMS = "android.permission.READ_CONTENT_RATING_SYSTEMS"; field public static final String READ_DEVICE_CONFIG = "android.permission.READ_DEVICE_CONFIG"; field public static final String READ_DREAM_STATE = "android.permission.READ_DREAM_STATE"; + field @FlaggedApi("android.security.afl_api") public static final String READ_FORENSIC_STATE = "android.permission.READ_FORENSIC_STATE"; field public static final String READ_GLOBAL_APP_SEARCH_DATA = "android.permission.READ_GLOBAL_APP_SEARCH_DATA"; field @FlaggedApi("android.content.pm.get_resolved_apk_path") public static final String READ_INSTALLED_SESSION_PATHS = "android.permission.READ_INSTALLED_SESSION_PATHS"; field public static final String READ_INSTALL_SESSIONS = "android.permission.READ_INSTALL_SESSIONS"; @@ -528,6 +533,7 @@ package android { field public static final int config_systemCallStreaming = 17039431; // 0x1040047 field public static final int config_systemCompanionDeviceProvider = 17039417; // 0x1040039 field public static final int config_systemContacts = 17039403; // 0x104002b + field @FlaggedApi("android.content.pm.sdk_dependency_installer") public static final int config_systemDependencyInstaller; field public static final int config_systemFinancedDeviceController = 17039430; // 0x1040046 field public static final int config_systemGallery = 17039399; // 0x1040027 field public static final int config_systemNotificationIntelligence = 17039413; // 0x1040035 @@ -1336,8 +1342,10 @@ package android.app.admin { public class DevicePolicyManager { method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public int checkProvisioningPrecondition(@NonNull String, @NonNull String); method @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_AUDIT_LOGGING) public void clearAuditLogEventCallback(); - method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException; + method @Deprecated @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createAndProvisionManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException; + method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public android.os.UserHandle createManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams) throws android.app.admin.ProvisioningException; method @Nullable public android.content.Intent createProvisioningIntentFromNfcIntent(@NonNull android.content.Intent); + method @FlaggedApi("android.app.admin.flags.split_create_managed_profile_enabled") @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void finalizeCreateManagedProfile(@NonNull android.app.admin.ManagedProfileProvisioningParams, @NonNull android.os.UserHandle) throws android.app.admin.ProvisioningException; method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void finalizeWorkProfileProvisioning(@NonNull android.os.UserHandle, @Nullable android.accounts.Account); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS) public java.util.Set<java.lang.Integer> getApplicationExemptions(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException; method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle); @@ -1932,6 +1940,7 @@ package android.app.backup { method public android.os.IBinder getBinder(); method public long getCurrentRestoreSet(); method public int getNextFullRestoreDataChunk(android.os.ParcelFileDescriptor); + method @FlaggedApi("com.android.server.backup.enable_restricted_mode_changes") @NonNull public java.util.List<java.lang.String> getPackagesThatShouldNotUseRestrictedMode(@NonNull java.util.List<java.lang.String>, int); method public int getRestoreData(android.os.ParcelFileDescriptor); method public int getTransportFlags(); method public int initializeDevice(); @@ -4585,6 +4594,24 @@ package android.content.pm { } +package android.content.pm.dependencyinstaller { + + @FlaggedApi("android.content.pm.sdk_dependency_installer") public final class DependencyInstallerCallback implements android.os.Parcelable { + method public int describeContents(); + method public void onAllDependenciesResolved(@NonNull int[]); + method public void onFailureToResolveAllDependencies(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.dependencyinstaller.DependencyInstallerCallback> CREATOR; + } + + @FlaggedApi("android.content.pm.sdk_dependency_installer") public abstract class DependencyInstallerService extends android.app.Service { + ctor public DependencyInstallerService(); + method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent); + method public abstract void onDependenciesRequired(@NonNull java.util.List<android.content.pm.SharedLibraryInfo>, @NonNull android.content.pm.dependencyinstaller.DependencyInstallerCallback); + } + +} + package android.content.pm.dex { public class ArtManager { @@ -5045,15 +5072,27 @@ package android.hardware.biometrics { package android.hardware.camera2 { + public final class CameraCharacteristics extends android.hardware.camera2.CameraMetadata<android.hardware.camera2.CameraCharacteristics.Key<?>> { + field @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") @NonNull public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.SharedSessionConfiguration> SHARED_SESSION_CONFIGURATION; + } + public abstract class CameraDevice implements java.lang.AutoCloseable { method @Deprecated public abstract void createCustomCaptureSession(android.hardware.camera2.params.InputConfiguration, @NonNull java.util.List<android.hardware.camera2.params.OutputConfiguration>, int, @NonNull android.hardware.camera2.CameraCaptureSession.StateCallback, @Nullable android.os.Handler) throws android.hardware.camera2.CameraAccessException; field public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = 1; // 0x1 field public static final int SESSION_OPERATION_MODE_NORMAL = 0; // 0x0 + field @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public static final int SESSION_OPERATION_MODE_SHARED = 2; // 0x2 field public static final int SESSION_OPERATION_MODE_VENDOR_START = 32768; // 0x8000 } + public abstract static class CameraDevice.StateCallback { + method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public void onClientSharedAccessPriorityChanged(@NonNull android.hardware.camera2.CameraDevice, boolean); + method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public void onOpenedInSharedMode(@NonNull android.hardware.camera2.CameraDevice, boolean); + } + public final class CameraManager { + method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public boolean isCameraDeviceSharingSupported(@NonNull String) throws android.hardware.camera2.CameraAccessException; method @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openCamera(@NonNull String, int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException; + method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") @RequiresPermission(allOf={android.Manifest.permission.SYSTEM_CAMERA, android.Manifest.permission.CAMERA}) public void openSharedCamera(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraDevice.StateCallback) throws android.hardware.camera2.CameraAccessException; } public abstract static class CameraManager.AvailabilityCallback { @@ -5061,6 +5100,12 @@ package android.hardware.camera2 { method @RequiresPermission(android.Manifest.permission.CAMERA_OPEN_CLOSE_LISTENER) public void onCameraOpened(@NonNull String, @NonNull String); } + @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public abstract class CameraSharedCaptureSession extends android.hardware.camera2.CameraCaptureSession { + ctor public CameraSharedCaptureSession(); + method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public abstract int startStreaming(@NonNull java.util.List<android.view.Surface>, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.camera2.CameraCaptureSession.CaptureCallback) throws android.hardware.camera2.CameraAccessException; + method @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public abstract void stopStreaming() throws android.hardware.camera2.CameraAccessException; + } + } package android.hardware.camera2.extension { @@ -5169,6 +5214,142 @@ package android.hardware.camera2.params { field public static final int ROTATION_90 = 1; // 0x1 } + public final class SessionConfiguration implements android.os.Parcelable { + field @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public static final int SESSION_SHARED = 2; // 0x2 + } + + @FlaggedApi("com.android.internal.camera.flags.camera_multi_client") public final class SharedSessionConfiguration { + method @Nullable public android.graphics.ColorSpace getColorSpace(); + method @NonNull public java.util.List<android.hardware.camera2.params.SharedSessionConfiguration.SharedOutputConfiguration> getOutputStreamsInformation(); + } + + public static final class SharedSessionConfiguration.SharedOutputConfiguration { + method public int getDataspace(); + method public int getFormat(); + method public int getMirrorMode(); + method @Nullable public String getPhysicalCameraId(); + method @NonNull public android.util.Size getSize(); + method public long getStreamUseCase(); + method public int getSurfaceType(); + method public int getTimestampBase(); + method public long getUsage(); + method public boolean isReadoutTimestampEnabled(); + } + +} + +package android.hardware.contexthub { + + @FlaggedApi("android.chre.flags.offload_api") public class HubDiscoveryInfo { + method @NonNull public android.hardware.contexthub.HubEndpointInfo getHubEndpointInfo(); + method @Nullable public android.hardware.contexthub.HubServiceInfo getHubServiceInfo(); + } + + @FlaggedApi("android.chre.flags.offload_api") public class HubEndpoint { + method @Nullable public android.hardware.contexthub.IHubEndpointLifecycleCallback getLifecycleCallback(); + method @Nullable public android.hardware.contexthub.IHubEndpointMessageCallback getMessageCallback(); + method @NonNull public java.util.Collection<android.hardware.contexthub.HubServiceInfo> getServiceInfoCollection(); + method @Nullable public String getTag(); + method public int getVersion(); + } + + public static final class HubEndpoint.Builder { + ctor public HubEndpoint.Builder(@NonNull android.content.Context); + method @NonNull public android.hardware.contexthub.HubEndpoint build(); + method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setLifecycleCallback(@NonNull android.hardware.contexthub.IHubEndpointLifecycleCallback); + method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setLifecycleCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.IHubEndpointLifecycleCallback); + method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setMessageCallback(@NonNull android.hardware.contexthub.IHubEndpointMessageCallback); + method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setMessageCallback(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.contexthub.IHubEndpointMessageCallback); + method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setServiceInfoCollection(@NonNull java.util.Collection<android.hardware.contexthub.HubServiceInfo>); + method @NonNull public android.hardware.contexthub.HubEndpoint.Builder setTag(@NonNull String); + } + + @FlaggedApi("android.chre.flags.offload_api") public final class HubEndpointInfo implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.hardware.contexthub.HubEndpointInfo.HubEndpointIdentifier getIdentifier(); + method @NonNull public String getName(); + method @NonNull public java.util.Collection<java.lang.String> getRequiredPermissions(); + method @NonNull public java.util.Collection<android.hardware.contexthub.HubServiceInfo> getServiceInfoCollection(); + method @Nullable public String getTag(); + method public int getType(); + method public int getVersion(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubEndpointInfo> CREATOR; + field public static final int TYPE_APP = 2; // 0x2 + field public static final int TYPE_FRAMEWORK = 1; // 0x1 + field public static final int TYPE_HUB_ENDPOINT = 5; // 0x5 + field public static final int TYPE_NANOAPP = 4; // 0x4 + field public static final int TYPE_NATIVE = 3; // 0x3 + } + + public static class HubEndpointInfo.HubEndpointIdentifier { + method public long getEndpoint(); + method public long getHub(); + } + + @FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSession implements java.lang.AutoCloseable { + method public void close(); + method @Nullable public android.hardware.contexthub.HubServiceInfo getServiceInfo(); + method @NonNull public android.hardware.location.ContextHubTransaction<java.lang.Void> sendMessage(@NonNull android.hardware.contexthub.HubMessage); + } + + @FlaggedApi("android.chre.flags.offload_api") public class HubEndpointSessionResult { + method @NonNull public static android.hardware.contexthub.HubEndpointSessionResult accept(); + method @Nullable public String getReason(); + method public boolean isAccepted(); + method @NonNull public static android.hardware.contexthub.HubEndpointSessionResult reject(@NonNull String); + } + + @FlaggedApi("android.chre.flags.offload_api") public final class HubMessage implements android.os.Parcelable { + method @NonNull public static android.hardware.contexthub.HubMessage createMessage(int, @NonNull byte[]); + method @NonNull public static android.hardware.contexthub.HubMessage createMessage(int, @NonNull byte[], @NonNull android.hardware.contexthub.HubMessage.DeliveryParams); + method public int describeContents(); + method @NonNull public byte[] getMessageBody(); + method public int getMessageType(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubMessage> CREATOR; + } + + public static class HubMessage.DeliveryParams { + method public boolean isResponseRequired(); + method @NonNull public static android.hardware.contexthub.HubMessage.DeliveryParams makeBasic(); + method @NonNull public android.hardware.contexthub.HubMessage.DeliveryParams setResponseRequired(boolean); + } + + @FlaggedApi("android.chre.flags.offload_api") public final class HubServiceInfo implements android.os.Parcelable { + ctor public HubServiceInfo(@NonNull String, int, int, int, @NonNull android.os.ParcelableHolder); + method public int describeContents(); + method @NonNull public android.os.ParcelableHolder getExtendedInfo(); + method public int getFormat(); + method public int getMajorVersion(); + method public int getMinorVersion(); + method @NonNull public String getServiceDescriptor(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubServiceInfo> CREATOR; + field public static final int FORMAT_AIDL = 1; // 0x1 + field public static final int FORMAT_CUSTOM = 0; // 0x0 + field public static final int FORMAT_PW_RPC_PROTOBUF = 2; // 0x2 + } + + public static final class HubServiceInfo.Builder { + ctor public HubServiceInfo.Builder(@NonNull String, int, int, int); + method @NonNull public android.hardware.contexthub.HubServiceInfo build(); + method @NonNull public android.hardware.contexthub.HubServiceInfo.Builder setExtendedInfo(@Nullable android.os.Parcelable); + } + + @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointLifecycleCallback { + method public void onSessionClosed(@NonNull android.hardware.contexthub.HubEndpointSession, int); + method @NonNull public android.hardware.contexthub.HubEndpointSessionResult onSessionOpenRequest(@NonNull android.hardware.contexthub.HubEndpointInfo, @Nullable android.hardware.contexthub.HubServiceInfo); + method public void onSessionOpened(@NonNull android.hardware.contexthub.HubEndpointSession); + field public static final int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4; // 0x4 + field public static final int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3; // 0x3 + field public static final int REASON_UNSPECIFIED = 0; // 0x0 + } + + @FlaggedApi("android.chre.flags.offload_api") public interface IHubEndpointMessageCallback { + method public void onMessageReceived(@NonNull android.hardware.contexthub.HubEndpointSession, @NonNull android.hardware.contexthub.HubMessage); + } + } package android.hardware.devicestate { @@ -5301,6 +5482,7 @@ package android.hardware.display { method @Nullable @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration(); method public android.util.Pair<float[],float[]> getMinimumBrightnessCurve(); method public android.graphics.Point getStableDisplaySize(); + method @FlaggedApi("com.android.server.display.feature.flags.is_always_on_available_api") public boolean isAlwaysOnDisplayCurrentlyAvailable(); method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration); method @RequiresPermission(android.Manifest.permission.CONFIGURE_DISPLAY_BRIGHTNESS) public void setBrightnessConfigurationForDisplay(@NonNull android.hardware.display.BrightnessConfiguration, @NonNull String); method @Deprecated @RequiresPermission(android.Manifest.permission.CONTROL_DISPLAY_SATURATION) public void setSaturationLevel(float); @@ -6162,6 +6344,8 @@ package android.hardware.location { method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubClient createClient(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.app.PendingIntent, long); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> disableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> enableNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); + method @FlaggedApi("android.chre.flags.offload_api") @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public java.util.List<android.hardware.contexthub.HubDiscoveryInfo> findEndpoints(long); + method @FlaggedApi("android.chre.flags.offload_api") @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public java.util.List<android.hardware.contexthub.HubDiscoveryInfo> findEndpoints(@NonNull String); method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int[] findNanoAppOnHub(int, @NonNull android.hardware.location.NanoAppFilter); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int[] getContextHubHandles(); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubInfo getContextHubInfo(int); @@ -6169,13 +6353,17 @@ package android.hardware.location { method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int loadNanoApp(int, @NonNull android.hardware.location.NanoApp); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> loadNanoApp(@NonNull android.hardware.location.ContextHubInfo, @NonNull android.hardware.location.NanoAppBinary); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void openSession(@NonNull android.hardware.contexthub.HubEndpoint, @NonNull android.hardware.contexthub.HubEndpointInfo); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void openSession(@NonNull android.hardware.contexthub.HubEndpoint, @NonNull android.hardware.contexthub.HubEndpointInfo, @NonNull android.hardware.contexthub.HubServiceInfo); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.util.List<android.hardware.location.NanoAppState>> queryNanoApps(@NonNull android.hardware.location.ContextHubInfo); method @Deprecated public int registerCallback(@NonNull android.hardware.location.ContextHubManager.Callback); method @Deprecated public int registerCallback(android.hardware.location.ContextHubManager.Callback, android.os.Handler); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void registerEndpoint(@NonNull android.hardware.contexthub.HubEndpoint); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int sendMessage(int, int, @NonNull android.hardware.location.ContextHubMessage); method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public int unloadNanoApp(int); method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public android.hardware.location.ContextHubTransaction<java.lang.Void> unloadNanoApp(@NonNull android.hardware.location.ContextHubInfo, long); method @Deprecated public int unregisterCallback(@NonNull android.hardware.location.ContextHubManager.Callback); + method @FlaggedApi("android.chre.flags.offload_api") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregisterEndpoint(@NonNull android.hardware.contexthub.HubEndpoint); field public static final int AUTHORIZATION_DENIED = 0; // 0x0 field public static final int AUTHORIZATION_DENIED_GRACE_PERIOD = 1; // 0x1 field public static final int AUTHORIZATION_GRANTED = 2; // 0x2 @@ -6231,6 +6419,8 @@ package android.hardware.location { field public static final int RESULT_SUCCESS = 0; // 0x0 field public static final int TYPE_DISABLE_NANOAPP = 3; // 0x3 field public static final int TYPE_ENABLE_NANOAPP = 2; // 0x2 + field @FlaggedApi("android.chre.flags.offload_api") public static final int TYPE_HUB_MESSAGE_DEFAULT = 6; // 0x6 + field @FlaggedApi("android.chre.flags.offload_api") public static final int TYPE_HUB_MESSAGE_REQUIRES_RESPONSE = 7; // 0x7 field public static final int TYPE_LOAD_NANOAPP = 0; // 0x0 field public static final int TYPE_QUERY_NANOAPPS = 4; // 0x4 field public static final int TYPE_RELIABLE_MESSAGE = 5; // 0x5 @@ -7464,6 +7654,7 @@ package android.media { } public final class AudioPlaybackConfiguration implements android.os.Parcelable { + method @FlaggedApi("android.media.audio.routed_device_ids") @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List<android.media.AudioDeviceInfo> getAudioDeviceInfos(); method public int getChannelMask(); method public int getClientPid(); method public int getClientUid(); @@ -7618,7 +7809,7 @@ package android.media { public final class MediaCas implements java.lang.AutoCloseable { method @FlaggedApi("android.media.tv.flags.set_resource_holder_retain") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public void setResourceHolderRetain(boolean); - method @FlaggedApi("com.android.media.flags.update_client_profile_priority") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean updateResourcePriority(int, int); + method @FlaggedApi("android.media.tv.flags.mediacas_update_client_profile_priority") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean updateResourcePriority(int, int); } public final class MediaCodec { @@ -7957,6 +8148,23 @@ package android.media.musicrecognition { } +package android.media.quality { + + @FlaggedApi("android.media.tv.flags.media_quality_fw") public final class MediaQualityManager { + method @NonNull public java.util.List<java.lang.String> getPictureProfileAllowList(); + method @NonNull public java.util.List<java.lang.String> getPictureProfilePackageNames(); + method @NonNull public java.util.List<android.media.quality.PictureProfile> getPictureProfilesByPackage(@NonNull String); + method public void setPictureProfileAllowList(@NonNull java.util.List<java.lang.String>); + } + + public static final class PictureProfile.Builder { + method @NonNull public android.media.quality.PictureProfile.Builder setInputId(@NonNull String); + method @NonNull public android.media.quality.PictureProfile.Builder setPackageName(@NonNull String); + method @NonNull public android.media.quality.PictureProfile.Builder setProfileType(int); + } + +} + package android.media.session { public final class MediaSessionManager { @@ -8249,18 +8457,96 @@ package android.media.tv { @FlaggedApi("android.media.tv.flags.tif_extension_standardization") public final class TvInputServiceExtensionManager { method @RequiresPermission(android.Manifest.permission.TV_INPUT_HARDWARE) public int registerExtensionIBinder(@NonNull String, @NonNull android.os.IBinder); - field public static final String IBROADCAST_TIME = "android.media.tv.extension.time.BroadcastTime"; + field public static final String IANALOG_ATTRIBUTE_INTERFACE = "android.media.tv.extension.analog.IAnalogAttributeInterface"; + field public static final String IANALOG_AUDIO_INFO = "android.media.tv.extension.signal.IAnalogAudioInfo"; + field public static final String IAUDIO_SIGNAL_INFO = "android.media.tv.extension.signal.IAudioSignalInfo"; + field public static final String IAUDIO_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.IAudioSignalInfoListener"; + field public static final String IBROADCAST_TIME = "android.media.tv.extension.time.IBroadcastTime"; + field public static final String ICAM_APP_INFO_LISTENER = "android.media.tv.extension.cam.ICamAppInfoListener"; field public static final String ICAM_APP_INFO_SERVICE = "android.media.tv.extension.cam.ICamAppInfoService"; + field public static final String ICAM_DRM_INFO_LISTENER = "android.media.tv.extension.cam.ICamDrmInfoListener"; + field public static final String ICAM_HOST_CONTROL_ASK_RELEASE_REPLY_CALLBACK = "android.media.tv.extension.cam.ICamHostControlAskReleaseReplyCallback"; + field public static final String ICAM_HOST_CONTROL_INFO_LISTENER = "android.media.tv.extension.cam.ICamHostControlInfoListener"; + field public static final String ICAM_HOST_CONTROL_SERVICE = "android.media.tv.extension.cam.ICamHostControlService"; + field public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG = "android.media.tv.extension.cam.ICamHostControlTuneQuietlyFlag"; + field public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG_LISTENER = "android.media.tv.extension.cam.ICamHostControlTuneQuietlyFlagListener"; + field public static final String ICAM_INFO_LISTENER = "android.media.tv.extension.cam.ICamInfoListener"; + field public static final String ICAM_MONITORING_SERVICE = "android.media.tv.extension.cam.ICamMonitoringService"; + field public static final String ICAM_PIN_CAPABILITY_LISTENER = "android.media.tv.extension.cam.ICamPinCapabilityListener"; + field public static final String ICAM_PIN_SERVICE = "android.media.tv.extension.cam.ICamPinService"; + field public static final String ICAM_PIN_STATUS_LISTENER = "android.media.tv.extension.cam.ICamPinStatusListener"; + field public static final String ICAM_PROFILE_INTERFACE = "android.media.tv.extension.cam.ICamProfileInterface"; + field public static final String ICHANNEL_LIST_TRANSFER = "android.media.tv.extension.servicedb.IChannelListTransfer"; + field public static final String ICHANNEL_TUNED_INTERFACE = "android.media.tv.extension.tune.IChannelTunedInterface"; + field public static final String ICHANNEL_TUNED_LISTENER = "android.media.tv.extension.tune.IChannelTunedListener"; + field public static final String ICI_OPERATOR_INTERFACE = "android.media.tv.extension.cam.ICiOperatorInterface"; + field public static final String ICI_OPERATOR_LISTENER = "android.media.tv.extension.cam.ICiOperatorListener"; field public static final String ICLIENT_TOKEN = "android.media.tv.extension.clienttoken.IClientToken"; + field public static final String ICONTENT_CONTROL_SERVICE = "android.media.tv.extension.cam.IContentControlService"; field public static final String IDATA_SERVICE_SIGNAL_INFO = "android.media.tv.extension.teletext.IDataServiceSignalInfo"; + field public static final String IDATA_SERVICE_SIGNAL_INFO_LISTENER = "android.media.tv.extension.teletext.IDataServiceSignalInfoListener"; + field public static final String IDELETE_RECORDED_CONTENTS_CALLBACK = "android.media.tv.extension.pvr.IDeleteRecordedContentsCallback"; + field public static final String IDOWNLOADABLE_RATING_TABLE_MONITOR = "android.media.tv.extension.rating.IDownloadableRatingTableMonitor"; + field public static final String IENTER_MENU_ERROR_CALLBACK = "android.media.tv.extension.cam.IEnterMenuErrorCallback"; + field public static final String IEVENT_DOWNLOAD = "android.media.tv.extension.event.IEventDownload"; + field public static final String IEVENT_DOWNLOAD_LISTENER = "android.media.tv.extension.event.IEventDownloadListener"; + field public static final String IEVENT_DOWNLOAD_SESSION = "android.media.tv.extension.event.IEventDownloadSession"; field public static final String IEVENT_MONITOR = "android.media.tv.extension.event.IEventMonitor"; + field public static final String IEVENT_MONITOR_LISTENER = "android.media.tv.extension.event.IEventMonitorListener"; + field public static final String IFAVORITE_NETWORK = "android.media.tv.extension.scan.IFavoriteNetwork"; + field public static final String IFAVORITE_NETWORK_LISTENER = "android.media.tv.extension.scan.IFavoriteNetworkListener"; + field public static final String IGET_INFO_RECORDED_CONTENTS_CALLBACK = "android.media.tv.extension.pvr.IGetInfoRecordedContentsCallback"; + field public static final String IHDMI_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.IHdmiSignalInfoListener"; field public static final String IHDMI_SIGNAL_INTERFACE = "android.media.tv.extension.signal.IHdmiSignalInterface"; + field public static final String IHDPLUS_INFO = "android.media.tv.extension.scan.IHDPlusInfo"; + field public static final String ILCNV2_CHANNEL_LIST = "android.media.tv.extension.scan.ILcnV2ChannelList"; + field public static final String ILCNV2_CHANNEL_LIST_LISTENER = "android.media.tv.extension.scan.ILcnV2ChannelListListener"; + field public static final String ILCN_CONFLICT = "android.media.tv.extension.scan.ILcnConflict"; + field public static final String ILCN_CONFLICT_LISTENER = "android.media.tv.extension.scan.ILcnConflictListener"; + field public static final String IMMI_INTERFACE = "android.media.tv.extension.cam.IMmiInterface"; + field public static final String IMMI_SESSION = "android.media.tv.extension.cam.IMmiSession"; + field public static final String IMMI_STATUS_CALLBACK = "android.media.tv.extension.cam.IMmiStatusCallback"; + field public static final String IMUX_TUNE = "android.media.tv.extension.tune.IMuxTune"; + field public static final String IMUX_TUNE_SESSION = "android.media.tv.extension.tune.IMuxTuneSession"; field public static final String IOAD_UPDATE_INTERFACE = "android.media.tv.extension.oad.IOadUpdateInterface"; + field public static final String IOPERATOR_DETECTION = "android.media.tv.extension.scan.IOperatorDetection"; + field public static final String IOPERATOR_DETECTION_LISTENER = "android.media.tv.extension.scan.IOperatorDetectionListener"; + field public static final String IPMT_RATING_INTERFACE = "android.media.tv.extension.rating.IPmtRatingInterface"; + field public static final String IPMT_RATING_LISTENER = "android.media.tv.extension.rating.IPmtRatingListener"; + field public static final String IPROGRAM_INFO = "android.media.tv.extension.rating.IProgramInfo"; + field public static final String IPROGRAM_INFO_LISTENER = "android.media.tv.extension.rating.IProgramInfoListener"; field public static final String IRATING_INTERFACE = "android.media.tv.extension.rating.IRatingInterface"; field public static final String IRECORDED_CONTENTS = "android.media.tv.extension.pvr.IRecordedContents"; + field public static final String IREGION_CHANNEL_LIST = "android.media.tv.extension.scan.IRegionChannelList"; + field public static final String IREGION_CHANNEL_LIST_LISTENER = "android.media.tv.extension.scan.IRegionChannelListListener"; + field public static final String ISCAN_BACKGROUND_SERVICE_UPDATE = "android.media.tv.extension.scanbsu.IScanBackgroundServiceUpdate"; + field public static final String ISCAN_BACKGROUND_SERVICE_UPDATE_LISTENER = "android.media.tv.extension.scanbsu.IScanBackgroundServiceUpdateListener"; field public static final String ISCAN_INTERFACE = "android.media.tv.extension.scan.IScanInterface"; + field public static final String ISCAN_LISTENER = "android.media.tv.extension.scan.IScanListener"; + field public static final String ISCAN_SAT_SEARCH = "android.media.tv.extension.scan.IScanSatSearch"; + field public static final String ISCAN_SESSION = "android.media.tv.extension.scan.IScanSession"; field public static final String ISCREEN_MODE_SETTINGS = "android.media.tv.extension.screenmode.IScreenModeSettings"; + field public static final String ISERVICE_LIST = "android.media.tv.extension.servicedb.IServiceList"; + field public static final String ISERVICE_LIST_EDIT = "android.media.tv.extension.servicedb.IServiceListEdit"; field public static final String ISERVICE_LIST_EDIT_LISTENER = "android.media.tv.extension.servicedb.IServiceListEditListener"; + field public static final String ISERVICE_LIST_EXPORT_LISTENER = "android.media.tv.extension.servicedb.IServiceListExportListener"; + field public static final String ISERVICE_LIST_EXPORT_SESSION = "android.media.tv.extension.servicedb.IServiceListExportSession"; + field public static final String ISERVICE_LIST_IMPORT_LISTENER = "android.media.tv.extension.servicedb.IServiceListImportListener"; + field public static final String ISERVICE_LIST_IMPORT_SESSION = "android.media.tv.extension.servicedb.IServiceListImportSession"; + field public static final String ISERVICE_LIST_SET_CHANNEL_LIST_LISTENER = "android.media.tv.extension.servicedb.IServiceListSetChannelListListener"; + field public static final String ISERVICE_LIST_SET_CHANNEL_LIST_SESSION = "android.media.tv.extension.servicedb.IServiceListSetChannelListSession"; + field public static final String ISERVICE_LIST_TRANSFER_INTERFACE = "android.media.tv.extension.servicedb.IServiceListTransferInterface"; + field public static final String ITARGET_REGION = "android.media.tv.extension.scan.ITargetRegion"; + field public static final String ITARGET_REGION_LISTENER = "android.media.tv.extension.scan.ITargetRegionListener"; + field public static final String ITELETEXT_PAGE_SUB_CODE = "android.media.tv.extension.teletext.ITeletextPageSubCode"; + field public static final String ITKGS_INFO = "android.media.tv.extension.scan.ITkgsInfo"; + field public static final String ITKGS_INFO_LISTENER = "android.media.tv.extension.scan.ITkgsInfoListener"; + field public static final String ITUNER_FRONTEND_SIGNAL_INFO_INTERFACE = "android.media.tv.extension.signal.ITunerFrontendSignalInfoInterface"; + field public static final String ITUNER_FRONTEND_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.ITunerFrontendSignalInfoListener"; + field public static final String IVBI_RATING_INTERFACE = "android.media.tv.extension.rating.IVbiRatingInterface"; + field public static final String IVBI_RATING_LISTENER = "android.media.tv.extension.rating.IVbiRatingListener"; + field public static final String IVIDEO_SIGNAL_INFO = "android.media.tv.extension.signal.IVideoSignalInfo"; + field public static final String IVIDEO_SIGNAL_INFO_LISTENER = "android.media.tv.extension.signal.IVideoSignalInfoListener"; field public static final int REGISTER_FAIL_IMPLEMENTATION_NOT_STANDARDIZED = 2; // 0x2 field public static final int REGISTER_FAIL_NAME_NOT_STANDARDIZED = 1; // 0x1 field public static final int REGISTER_FAIL_REMOTE_EXCEPTION = 3; // 0x3 @@ -12570,6 +12856,29 @@ package android.security.advancedprotection { } +package android.security.forensic { + + @FlaggedApi("android.security.afl_api") public class ForensicManager { + method @RequiresPermission(android.Manifest.permission.READ_FORENSIC_STATE) public void addStateCallback(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.MANAGE_FORENSIC_STATE) public void disable(@NonNull java.util.concurrent.Executor, @NonNull android.security.forensic.ForensicManager.CommandCallback); + method @RequiresPermission(android.Manifest.permission.MANAGE_FORENSIC_STATE) public void enable(@NonNull java.util.concurrent.Executor, @NonNull android.security.forensic.ForensicManager.CommandCallback); + method @RequiresPermission(android.Manifest.permission.READ_FORENSIC_STATE) public void removeStateCallback(@NonNull java.util.function.Consumer<java.lang.Integer>); + field public static final int ERROR_DATA_SOURCE_UNAVAILABLE = 4; // 0x4 + field public static final int ERROR_PERMISSION_DENIED = 1; // 0x1 + field public static final int ERROR_TRANSPORT_UNAVAILABLE = 3; // 0x3 + field public static final int ERROR_UNKNOWN = 0; // 0x0 + field public static final int STATE_DISABLED = 1; // 0x1 + field public static final int STATE_ENABLED = 2; // 0x2 + field public static final int STATE_UNKNOWN = 0; // 0x0 + } + + public static interface ForensicManager.CommandCallback { + method public void onFailure(int); + method public void onSuccess(); + } + +} + package android.security.keystore { public class AndroidKeyStoreProvider extends java.security.Provider { @@ -14969,6 +15278,32 @@ package android.telephony { method @NonNull public android.telephony.CellIdentityWcdma sanitizeLocationInfo(); } + @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") public final class CellularIdentifierDisclosure implements android.os.Parcelable { + method public int describeContents(); + method public int getCellularIdentifier(); + method public int getNasProtocolMessage(); + method @NonNull public String getPlmn(); + method public boolean isEmergency(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CELLULAR_IDENTIFIER_IMEI = 2; // 0x2 + field public static final int CELLULAR_IDENTIFIER_IMSI = 1; // 0x1 + field public static final int CELLULAR_IDENTIFIER_SUCI = 3; // 0x3 + field public static final int CELLULAR_IDENTIFIER_UNKNOWN = 0; // 0x0 + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellularIdentifierDisclosure> CREATOR; + field public static final int NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST = 1; // 0x1 + field public static final int NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE = 6; // 0x6 + field public static final int NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST = 9; // 0x9 + field public static final int NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST = 10; // 0xa + field public static final int NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST = 8; // 0x8 + field public static final int NAS_PROTOCOL_MESSAGE_DETACH_REQUEST = 3; // 0x3 + field public static final int NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE = 2; // 0x2 + field public static final int NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION = 11; // 0xb + field public static final int NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST = 5; // 0x5 + field public static final int NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST = 7; // 0x7 + field public static final int NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST = 4; // 0x4 + field public static final int NAS_PROTOCOL_MESSAGE_UNKNOWN = 0; // 0x0 + } + public final class DataFailCause { field @Deprecated public static final int VSNCP_APN_UNATHORIZED = 2238; // 0x8be } @@ -15420,6 +15755,75 @@ package android.telephony { field public static final int USER_NOT_MEMBER_OF_CUG = 87; // 0x57 } + @FlaggedApi("com.android.internal.telephony.flags.security_algorithms_update_indications") public final class SecurityAlgorithmUpdate implements android.os.Parcelable { + method public int describeContents(); + method public int getConnectionEvent(); + method public int getEncryption(); + method public int getIntegrity(); + method public boolean isUnprotectedEmergency(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CONNECTION_EVENT_AS_SIGNALLING_5G = 11; // 0xb + field public static final int CONNECTION_EVENT_AS_SIGNALLING_LTE = 5; // 0x5 + field public static final int CONNECTION_EVENT_CS_SIGNALLING_3G = 2; // 0x2 + field public static final int CONNECTION_EVENT_CS_SIGNALLING_GSM = 0; // 0x0 + field public static final int CONNECTION_EVENT_NAS_SIGNALLING_5G = 10; // 0xa + field public static final int CONNECTION_EVENT_NAS_SIGNALLING_LTE = 4; // 0x4 + field public static final int CONNECTION_EVENT_PS_SIGNALLING_3G = 3; // 0x3 + field public static final int CONNECTION_EVENT_PS_SIGNALLING_GPRS = 1; // 0x1 + field public static final int CONNECTION_EVENT_VOLTE_RTP = 8; // 0x8 + field public static final int CONNECTION_EVENT_VOLTE_RTP_SOS = 9; // 0x9 + field public static final int CONNECTION_EVENT_VOLTE_SIP = 6; // 0x6 + field public static final int CONNECTION_EVENT_VOLTE_SIP_SOS = 7; // 0x7 + field public static final int CONNECTION_EVENT_VONR_RTP = 14; // 0xe + field public static final int CONNECTION_EVENT_VONR_RTP_SOS = 15; // 0xf + field public static final int CONNECTION_EVENT_VONR_SIP = 12; // 0xc + field public static final int CONNECTION_EVENT_VONR_SIP_SOS = 13; // 0xd + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SecurityAlgorithmUpdate> CREATOR; + field public static final int SECURITY_ALGORITHM_A50 = 0; // 0x0 + field public static final int SECURITY_ALGORITHM_A51 = 1; // 0x1 + field public static final int SECURITY_ALGORITHM_A52 = 2; // 0x2 + field public static final int SECURITY_ALGORITHM_A53 = 3; // 0x3 + field public static final int SECURITY_ALGORITHM_A54 = 4; // 0x4 + field public static final int SECURITY_ALGORITHM_AES_CBC = 71; // 0x47 + field public static final int SECURITY_ALGORITHM_AES_EDE3_CBC = 73; // 0x49 + field public static final int SECURITY_ALGORITHM_AES_GCM = 69; // 0x45 + field public static final int SECURITY_ALGORITHM_AES_GMAC = 70; // 0x46 + field public static final int SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128 = 101; // 0x65 + field public static final int SECURITY_ALGORITHM_DES_EDE3_CBC = 72; // 0x48 + field public static final int SECURITY_ALGORITHM_EEA0 = 41; // 0x29 + field public static final int SECURITY_ALGORITHM_EEA1 = 42; // 0x2a + field public static final int SECURITY_ALGORITHM_EEA2 = 43; // 0x2b + field public static final int SECURITY_ALGORITHM_EEA3 = 44; // 0x2c + field public static final int SECURITY_ALGORITHM_ENCR_AES_CBC = 100; // 0x64 + field public static final int SECURITY_ALGORITHM_ENCR_AES_GCM_16 = 99; // 0x63 + field public static final int SECURITY_ALGORITHM_GEA0 = 14; // 0xe + field public static final int SECURITY_ALGORITHM_GEA1 = 15; // 0xf + field public static final int SECURITY_ALGORITHM_GEA2 = 16; // 0x10 + field public static final int SECURITY_ALGORITHM_GEA3 = 17; // 0x11 + field public static final int SECURITY_ALGORITHM_GEA4 = 18; // 0x12 + field public static final int SECURITY_ALGORITHM_GEA5 = 19; // 0x13 + field public static final int SECURITY_ALGORITHM_HMAC_MD5_96 = 75; // 0x4b + field public static final int SECURITY_ALGORITHM_HMAC_SHA1_96 = 74; // 0x4a + field public static final int SECURITY_ALGORITHM_IMS_NULL = 67; // 0x43 + field public static final int SECURITY_ALGORITHM_NEA0 = 55; // 0x37 + field public static final int SECURITY_ALGORITHM_NEA1 = 56; // 0x38 + field public static final int SECURITY_ALGORITHM_NEA2 = 57; // 0x39 + field public static final int SECURITY_ALGORITHM_NEA3 = 58; // 0x3a + field public static final int SECURITY_ALGORITHM_ORYX = 124; // 0x7c + field public static final int SECURITY_ALGORITHM_OTHER = 114; // 0x72 + field public static final int SECURITY_ALGORITHM_RTP = 85; // 0x55 + field public static final int SECURITY_ALGORITHM_SIP_NO_IPSEC_CONFIG = 66; // 0x42 + field public static final int SECURITY_ALGORITHM_SIP_NULL = 68; // 0x44 + field public static final int SECURITY_ALGORITHM_SRTP_AES_COUNTER = 87; // 0x57 + field public static final int SECURITY_ALGORITHM_SRTP_AES_F8 = 88; // 0x58 + field public static final int SECURITY_ALGORITHM_SRTP_HMAC_SHA1 = 89; // 0x59 + field public static final int SECURITY_ALGORITHM_SRTP_NULL = 86; // 0x56 + field public static final int SECURITY_ALGORITHM_UEA0 = 29; // 0x1d + field public static final int SECURITY_ALGORITHM_UEA1 = 30; // 0x1e + field public static final int SECURITY_ALGORITHM_UEA2 = 31; // 0x1f + field public static final int SECURITY_ALGORITHM_UNKNOWN = 113; // 0x71 + } + public class ServiceState implements android.os.Parcelable { method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int); method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int); @@ -15644,6 +16048,7 @@ package android.telephony { field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final int EVENT_CALL_FORWARDING_INDICATOR_CHANGED = 4; // 0x4 field public static final int EVENT_CALL_STATE_CHANGED = 6; // 0x6 field public static final int EVENT_CARRIER_NETWORK_CHANGED = 17; // 0x11 + field @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED = 47; // 0x2f field @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_CELL_INFO_CHANGED = 11; // 0xb field @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public static final int EVENT_CELL_LOCATION_CHANGED = 5; // 0x5 field public static final int EVENT_DATA_ACTIVATION_STATE_CHANGED = 19; // 0x13 @@ -15668,6 +16073,7 @@ package android.telephony { field @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public static final int EVENT_PRECISE_DATA_CONNECTION_STATE_CHANGED = 13; // 0xd field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_RADIO_POWER_STATE_CHANGED = 24; // 0x18 field @RequiresPermission(allOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, android.Manifest.permission.ACCESS_FINE_LOCATION}) public static final int EVENT_REGISTRATION_FAILURE = 31; // 0x1f + field @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int EVENT_SECURITY_ALGORITHMS_CHANGED = 46; // 0x2e field public static final int EVENT_SERVICE_STATE_CHANGED = 1; // 0x1 field public static final int EVENT_SIGNAL_STRENGTHS_CHANGED = 9; // 0x9 field public static final int EVENT_SIGNAL_STRENGTH_CHANGED = 2; // 0x2 @@ -15686,6 +16092,10 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallStatesChanged(@NonNull java.util.List<android.telephony.CallState>); } + @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") public static interface TelephonyCallback.CellularIdentifierDisclosedListener { + method public void onCellularIdentifierDisclosedChanged(@NonNull android.telephony.CellularIdentifierDisclosure); + } + public static interface TelephonyCallback.DataEnabledListener { method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onDataEnabledChanged(boolean, int); } @@ -15724,6 +16134,10 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onRadioPowerStateChanged(int); } + @FlaggedApi("com.android.internal.telephony.flags.security_algorithms_update_indications") public static interface TelephonyCallback.SecurityAlgorithmsListener { + method public void onSecurityAlgorithmsChanged(@NonNull android.telephony.SecurityAlgorithmUpdate); + } + @FlaggedApi("com.android.internal.telephony.flags.simultaneous_calling_indications") public static interface TelephonyCallback.SimultaneousCellularCallingSupportListener { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void onSimultaneousCellularCallingSubscriptionsChanged(@NonNull java.util.Set<java.lang.Integer>); } diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 119271390b94..44bcc2a737b9 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2318,7 +2318,7 @@ package android.net.wifi.sharedconnectivity.app { public class SharedConnectivityManager { method @Nullable public static android.net.wifi.sharedconnectivity.app.SharedConnectivityManager create(@NonNull android.content.Context, @NonNull String, @NonNull String); - method @FlaggedApi("com.android.wifi.flags.shared_connectivity_broadcast_receiver_test_api") @NonNull public android.content.BroadcastReceiver getBroadcastReceiver(); + method @NonNull public android.content.BroadcastReceiver getBroadcastReceiver(); method @Nullable public android.content.ServiceConnection getServiceConnection(); method public void setService(@Nullable android.os.IInterface); } @@ -3240,6 +3240,7 @@ package android.service.quickaccesswallet { method @Nullable public android.content.Intent createWalletIntent(); method @Nullable public android.content.Intent createWalletSettingsIntent(); method public void disconnect(); + method @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") public void getGestureTargetActivityPendingIntent(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.GesturePendingIntentCallback); method public void getWalletCards(@NonNull android.service.quickaccesswallet.GetWalletCardsRequest, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.OnWalletCardsRetrievedCallback); method public void getWalletCards(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.GetWalletCardsRequest, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.OnWalletCardsRetrievedCallback); method public void getWalletPendingIntent(@NonNull java.util.concurrent.Executor, @NonNull android.service.quickaccesswallet.QuickAccessWalletClient.WalletPendingIntentCallback); @@ -3251,6 +3252,10 @@ package android.service.quickaccesswallet { method public void selectWalletCard(@NonNull android.service.quickaccesswallet.SelectWalletCardRequest); } + @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") public static interface QuickAccessWalletClient.GesturePendingIntentCallback { + method @FlaggedApi("android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap") public void onGesturePendingIntentRetrieved(@Nullable android.app.PendingIntent); + } + public static interface QuickAccessWalletClient.OnWalletCardsRetrievedCallback { method public void onWalletCardRetrievalError(@NonNull android.service.quickaccesswallet.GetWalletCardsError); method public void onWalletCardsRetrieved(@NonNull android.service.quickaccesswallet.GetWalletCardsResponse); @@ -3393,6 +3398,10 @@ package android.telephony { ctor public BarringInfo.BarringServiceInfo(int, boolean, int, int); } + @FlaggedApi("com.android.internal.telephony.flags.cellular_identifier_disclosure_indications") public final class CellularIdentifierDisclosure implements android.os.Parcelable { + ctor public CellularIdentifierDisclosure(int, int, @NonNull String, boolean); + } + public class MbmsDownloadSession implements java.lang.AutoCloseable { field public static final String MBMS_DOWNLOAD_SERVICE_OVERRIDE_METADATA = "mbms-download-service-override"; } @@ -3420,6 +3429,10 @@ package android.telephony { ctor @Deprecated public PreciseDataConnectionState(int, int, int, @NonNull String, @Nullable android.net.LinkProperties, int); } + @FlaggedApi("com.android.internal.telephony.flags.security_algorithms_update_indications") public final class SecurityAlgorithmUpdate implements android.os.Parcelable { + ctor public SecurityAlgorithmUpdate(int, int, int, boolean); + } + public class ServiceState implements android.os.Parcelable { method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo); method public int getDataNetworkType(); diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt index 08bb08254476..c2fac70d1f68 100644 --- a/core/api/test-lint-baseline.txt +++ b/core/api/test-lint-baseline.txt @@ -1,4 +1,10 @@ // Baseline format: 1.0 +ActionValue: android.view.contentcapture.ViewNode.ViewStructureImpl#EXTRA_VIRTUAL_STRUCTURE_TYPE: + Inconsistent extra value; expected `android.view.contentcapture.extra.VIRTUAL_STRUCTURE_TYPE`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE` +ActionValue: android.view.contentcapture.ViewNode.ViewStructureImpl#EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER: + Inconsistent extra value; expected `android.view.contentcapture.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER`, was `android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER` + + BannedThrow: android.os.vibrator.persistence.VibrationXmlSerializer#serialize(android.os.VibrationEffect, java.io.Writer): Methods must not throw unchecked exceptions diff --git a/core/java/Android.bp b/core/java/Android.bp index cf5ebbaa37b4..bc38294279a8 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -232,6 +232,8 @@ aidl_interface { "android.hardware.power-aidl", ], srcs: [ + "android/os/CpuHeadroomParamsInternal.aidl", + "android/os/GpuHeadroomParamsInternal.aidl", "android/os/IHintManager.aidl", "android/os/IHintSession.aidl", ], diff --git a/core/java/android/adaptiveauth/OWNERS b/core/java/android/adaptiveauth/OWNERS index bc8efa92c16f..4310d1a3a9db 100644 --- a/core/java/android/adaptiveauth/OWNERS +++ b/core/java/android/adaptiveauth/OWNERS @@ -1 +1 @@ -include /services/core/java/com/android/server/security/adaptiveauthentication/OWNERS
\ No newline at end of file +include /services/core/java/com/android/server/security/authenticationpolicy/OWNERS
\ No newline at end of file diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 8b37dbd04bec..ce0ec602e612 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1624,9 +1624,19 @@ public class AppOpsManager { /** @hide Access to read oxygen saturation. */ public static final int OP_READ_OXYGEN_SATURATION = AppOpEnums.APP_OP_READ_OXYGEN_SATURATION; + /** @hide Access to write system preferences. */ + public static final int OP_WRITE_SYSTEM_PREFERENCES = + AppOpEnums.APP_OP_WRITE_SYSTEM_PREFERENCES; + + /** @hide Access to audio playback and control APIs. */ + public static final int OP_CONTROL_AUDIO = AppOpEnums.APP_OP_CONTROL_AUDIO; + + /** @hide Similar to {@link OP_CONTROL_AUDIO}, but doesn't require capabilities. */ + public static final int OP_CONTROL_AUDIO_PARTIAL = AppOpEnums.APP_OP_CONTROL_AUDIO_PARTIAL; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public static final int _NUM_OP = 153; + public static final int _NUM_OP = 156; /** * All app ops represented as strings. @@ -1783,6 +1793,9 @@ public class AppOpsManager { OPSTR_READ_SKIN_TEMPERATURE, OPSTR_RANGING, OPSTR_READ_OXYGEN_SATURATION, + OPSTR_WRITE_SYSTEM_PREFERENCES, + OPSTR_CONTROL_AUDIO, + OPSTR_CONTROL_AUDIO_PARTIAL, }) public @interface AppOpString {} @@ -2540,6 +2553,15 @@ public class AppOpsManager { @FlaggedApi(Flags.FLAG_RANGING_PERMISSION_ENABLED) public static final String OPSTR_RANGING = "android:ranging"; + /** @hide Access to system preferences write services */ + public static final String OPSTR_WRITE_SYSTEM_PREFERENCES = "android:write_system_preferences"; + + /** @hide Access to audio playback and control APIs */ + public static final String OPSTR_CONTROL_AUDIO = "android:control_audio"; + + /** @hide Access to a audio playback and control APIs without capability requirements */ + public static final String OPSTR_CONTROL_AUDIO_PARTIAL = "android:control_audio_partial"; + /** {@link #sAppOpsToNote} not initialized yet for this op */ private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0; /** Should not collect noting of this app-op in {@link #sAppOpsToNote} */ @@ -2656,6 +2678,7 @@ public class AppOpsManager { OP_RECEIVE_SANDBOX_TRIGGER_AUDIO, OP_MEDIA_ROUTING_CONTROL, OP_READ_SYSTEM_GRAMMATICAL_GENDER, + OP_WRITE_SYSTEM_PREFERENCES, }; @SuppressWarnings("FlaggedApi") @@ -3144,6 +3167,14 @@ public class AppOpsManager { Flags.replaceBodySensorPermissionEnabled() ? HealthPermissions.READ_OXYGEN_SATURATION : null) .setDefaultMode(AppOpsManager.MODE_ALLOWED).build(), + new AppOpInfo.Builder(OP_WRITE_SYSTEM_PREFERENCES, OPSTR_WRITE_SYSTEM_PREFERENCES, + "WRITE_SYSTEM_PREFERENCES").setPermission( + com.android.settingslib.flags.Flags.writeSystemPreferencePermissionEnabled() + ? Manifest.permission.WRITE_SYSTEM_PREFERENCES : null).build(), + new AppOpInfo.Builder(OP_CONTROL_AUDIO, OPSTR_CONTROL_AUDIO, + "CONTROL_AUDIO").setDefaultMode(AppOpsManager.MODE_FOREGROUND).build(), + new AppOpInfo.Builder(OP_CONTROL_AUDIO_PARTIAL, OPSTR_CONTROL_AUDIO_PARTIAL, + "CONTROL_AUDIO_PARTIAL").setDefaultMode(AppOpsManager.MODE_FOREGROUND).build(), }; // The number of longs needed to form a full bitmask of app ops diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index e247916915d6..7e0a9b69b7bd 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -16,6 +16,7 @@ package android.app; +import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM; import static android.app.PropertyInvalidatedCache.createSystemCacheKey; import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_COLORED; import static android.app.admin.DevicePolicyResources.Drawables.Style.SOLID_NOT_COLORED; @@ -783,43 +784,24 @@ public class ApplicationPackageManager extends PackageManager { } /** + * The API and cache name for hasSystemFeature. + */ + private static final String HAS_SYSTEM_FEATURE_API = "has_system_feature"; + + /** * Identifies a single hasSystemFeature query. */ - @Immutable - private static final class HasSystemFeatureQuery { - public final String name; - public final int version; - public HasSystemFeatureQuery(String n, int v) { - name = n; - version = v; - } - @Override - public String toString() { - return String.format("HasSystemFeatureQuery(name=\"%s\", version=%d)", - name, version); - } - @Override - public boolean equals(@Nullable Object o) { - if (o instanceof HasSystemFeatureQuery) { - HasSystemFeatureQuery r = (HasSystemFeatureQuery) o; - return Objects.equals(name, r.name) && version == r.version; - } else { - return false; - } - } - @Override - public int hashCode() { - return Objects.hashCode(name) * 13 + version; - } - } + private record HasSystemFeatureQuery(String name, int version) {} // Make this cache relatively large. There are many system features and // none are ever invalidated. MPTS tests suggests that the cache should // hold at least 150 entries. private final static PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean> - mHasSystemFeatureCache = - new PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean>( - 256, createSystemCacheKey("has_system_feature")) { + mHasSystemFeatureCache = new PropertyInvalidatedCache<>( + new PropertyInvalidatedCache.Args(MODULE_SYSTEM) + .api(HAS_SYSTEM_FEATURE_API).maxEntries(256).isolateUids(false), + HAS_SYSTEM_FEATURE_API, null) { + @Override public Boolean recompute(HasSystemFeatureQuery query) { try { diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl index 961501503348..7a329cd541a2 100644 --- a/core/java/android/app/IActivityClientController.aidl +++ b/core/java/android/app/IActivityClientController.aidl @@ -112,8 +112,8 @@ interface IActivityClientController { oneway void requestMultiwindowFullscreen(in IBinder token, in int request, in IRemoteCallback callback); - oneway void startLockTaskModeByToken(in IBinder token); - oneway void stopLockTaskModeByToken(in IBinder token); + void startLockTaskModeByToken(in IBinder token); + void stopLockTaskModeByToken(in IBinder token); oneway void showLockTaskEscapeMessage(in IBinder token); void setTaskDescription(in IBinder token, in ActivityManager.TaskDescription values); diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 34a3ad19b270..a8412fa66609 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -358,7 +358,7 @@ interface IActivityManager { @UnsupportedAppUsage void resumeAppSwitches(); boolean bindBackupAgent(in String packageName, int backupRestoreMode, int targetUserId, - int backupDestination); + int backupDestination, boolean useRestrictedMode); void backupAgentCreated(in String packageName, in IBinder agent, int userId); void unbindBackupAgent(in ApplicationInfo appInfo); int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll, diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index 62820ad5a4d6..67f7bee4028e 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -18,6 +18,7 @@ package android.app; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -52,7 +53,9 @@ import android.view.IOnKeyguardExitResult; import android.view.IWindowManager; import android.view.WindowManagerGlobal; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.policy.IDeviceLockedStateListener; import com.android.internal.policy.IKeyguardDismissCallback; import com.android.internal.policy.IKeyguardLockedStateListener; import com.android.internal.util.Preconditions; @@ -253,6 +256,26 @@ public class KeyguardManager { private final ArrayMap<KeyguardLockedStateListener, Executor> mKeyguardLockedStateListeners = new ArrayMap<>(); + private final IDeviceLockedStateListener mIDeviceLockedStateListener = + new IDeviceLockedStateListener.Stub() { + @Override + public void onDeviceLockedStateChanged(boolean isDeviceLocked) { + if (!Flags.deviceUnlockListener()) { + return; + } + synchronized (mDeviceLockedStateListeners) { + mDeviceLockedStateListeners.forEach((listener, executor) -> { + executor.execute( + () -> listener.onDeviceLockedStateChanged(isDeviceLocked)); + }); + } + } + }; + + @GuardedBy("mDeviceLockedStateListeners") + private final ArrayMap<DeviceLockedStateListener, Executor> + mDeviceLockedStateListeners = new ArrayMap<>(); + /** * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics * if enrolled) for the current user of the device. The caller is expected to launch this @@ -1370,4 +1393,77 @@ public class KeyguardManager { } } } + + + /** + * Listener for device locked state changes. + */ + @FunctionalInterface + @FlaggedApi(Flags.FLAG_DEVICE_UNLOCK_LISTENER) + public interface DeviceLockedStateListener { + /** + * Callback function that executes when the device locked state changes. + */ + void onDeviceLockedStateChanged(boolean isDeviceLocked); + } + + + /** + * Registers a listener to execute when the device locked state changes. + * + * @param executor The {@link Executor} where the {@code listener} will be invoked + * @param listener The listener to add to receive device locked state changes. + * + * @see #isDeviceLocked() + * @see #removeDeviceLockedStateListener(DeviceLockedStateListener) + */ + @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) + @FlaggedApi(Flags.FLAG_DEVICE_UNLOCK_LISTENER) + public void addDeviceLockedStateListener(@NonNull @CallbackExecutor Executor executor, + @NonNull DeviceLockedStateListener listener) { + if (!Flags.deviceUnlockListener()) { + return; + } + + synchronized (mDeviceLockedStateListeners) { + mDeviceLockedStateListeners.put(listener, executor); + if (mDeviceLockedStateListeners.size() > 1) { + return; + } + try { + mTrustManager.registerDeviceLockedStateListener(mIDeviceLockedStateListener, + mContext.getDeviceId()); + } catch (RemoteException re) { + Log.d(TAG, "TrustManager service died", re); + } + } + } + + /** + * Unregisters a listener that executes when the device locked state changes. + * + * @param listener The listener to remove. + * + * @see #isDeviceLocked() + * @see #addDeviceLockedStateListener(Executor, DeviceLockedStateListener) + */ + @RequiresPermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) + @FlaggedApi(Flags.FLAG_DEVICE_UNLOCK_LISTENER) + public void removeDeviceLockedStateListener(@NonNull DeviceLockedStateListener listener) { + if (!Flags.deviceUnlockListener()) { + return; + } + + synchronized (mDeviceLockedStateListeners) { + mDeviceLockedStateListeners.remove(listener); + if (!mDeviceLockedStateListeners.isEmpty()) { + return; + } + try { + mTrustManager.unregisterDeviceLockedStateListener(mIDeviceLockedStateListener); + } catch (RemoteException re) { + Log.d(TAG, "TrustManager service died", re); + } + } + } } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 3d9c55c0f37a..1c23ec799599 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -811,11 +811,20 @@ public class Notification implements Parcelable } private static boolean isStandardLayout(int layoutId) { + // TODO: b/359128724 - Add to static list when inlining the flag. if (Flags.apiRichOngoing()) { if (layoutId == R.layout.notification_template_material_progress) { return true; } } + // TODO: b/378660052 - Add to static list when inlining the flag. + if (Flags.notificationsRedesignTemplates()) { + switch(layoutId) { + case R.layout.notification_2025_template_collapsed_base: + case R.layout.notification_2025_template_header: + return true; + } + } return STANDARD_LAYOUTS.contains(layoutId); } @@ -6718,7 +6727,7 @@ public class Notification implements Parcelable // Headers on their own are never colorized p.disallowColorization(); RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(), - R.layout.notification_template_header); + getHeaderLayoutResource()); resetNotificationHeader(header); bindNotificationHeader(header, p); return header; @@ -7478,9 +7487,21 @@ public class Notification implements Parcelable return clone; } + private int getHeaderLayoutResource() { + if (Flags.notificationsRedesignTemplates()) { + return R.layout.notification_2025_template_header; + } else { + return R.layout.notification_template_header; + } + } + @UnsupportedAppUsage private int getBaseLayoutResource() { - return R.layout.notification_template_material_base; + if (Flags.notificationsRedesignTemplates()) { + return R.layout.notification_2025_template_collapsed_base; + } else { + return R.layout.notification_template_material_base; + } } private int getHeadsUpBaseLayoutResource() { @@ -9499,7 +9520,6 @@ public class Notification implements Parcelable contentView.setViewVisibility(R.id.icon, View.GONE); contentView.setViewVisibility(R.id.conversation_face_pile, View.GONE); contentView.setViewVisibility(R.id.conversation_icon, View.VISIBLE); - contentView.setBoolean(R.id.conversation_icon, "setApplyCircularCrop", true); contentView.setImageViewIcon(R.id.conversation_icon, conversationIcon); } else if (mIsGroupConversation) { contentView.setViewVisibility(R.id.icon, View.GONE); diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index 1dc774285a32..e218418336c5 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -314,6 +314,14 @@ public class PropertyInvalidatedCache<Query, Result> { @GuardedBy("mLock") private long mMisses = 0; + // This counter tracks the number of times {@link #recompute} returned a null value. Null + // results are cached, or not, depending on instantiation arguments. Caching nulls when they + // should not be cached is a functional error. Failing to cache nulls that can be cached is a + // performance error. A non-zero value here means the cache should be examined to be sure + // that nulls are correctly cached, or not. + @GuardedBy("mLock") + private long mNulls = 0; + @GuardedBy("mLock") private long[] mSkips = new long[MAX_RESERVED_NONCE + 1]; @@ -374,6 +382,11 @@ public class PropertyInvalidatedCache<Query, Result> { private final String mCacheName; /** + * True if nulls are valid returns from recompute(). + */ + private final boolean mCacheNullResults; + + /** * The function that computes a Result, given a Query. This function is called on a * cache miss. */ @@ -509,6 +522,19 @@ public class PropertyInvalidatedCache<Query, Result> { } /** + * Return true if the entry is in the cache. + */ + boolean containsKey(Query query) { + final int uid = callerUid(); + var map = mCache.get(uid); + if (map != null) { + return map.containsKey(query); + } else { + return false; + } + } + + /** * Remove an entry from the cache. */ void remove(Query query) { @@ -1101,7 +1127,7 @@ public class PropertyInvalidatedCache<Query, Result> { * @hide */ public static record Args(@NonNull String mModule, @Nullable String mApi, - int mMaxEntries, boolean mIsolateUids, boolean mTestMode) { + int mMaxEntries, boolean mIsolateUids, boolean mTestMode, boolean mCacheNulls) { // Validation: the module must be one of the known module strings and the maxEntries must // be positive. @@ -1119,24 +1145,29 @@ public class PropertyInvalidatedCache<Query, Result> { null, // api 32, // maxEntries true, // isolateUids - false // testMode + false, // testMode + true // allowNulls ); } public Args api(@NonNull String api) { - return new Args(mModule, api, mMaxEntries, mIsolateUids, mTestMode); + return new Args(mModule, api, mMaxEntries, mIsolateUids, mTestMode, mCacheNulls); } public Args maxEntries(int val) { - return new Args(mModule, mApi, val, mIsolateUids, mTestMode); + return new Args(mModule, mApi, val, mIsolateUids, mTestMode, mCacheNulls); } public Args isolateUids(boolean val) { - return new Args(mModule, mApi, mMaxEntries, val, mTestMode); + return new Args(mModule, mApi, mMaxEntries, val, mTestMode, mCacheNulls); } public Args testMode(boolean val) { - return new Args(mModule, mApi, mMaxEntries, mIsolateUids, val); + return new Args(mModule, mApi, mMaxEntries, mIsolateUids, val, mCacheNulls); + } + + public Args cacheNulls(boolean val) { + return new Args(mModule, mApi, mMaxEntries, mIsolateUids, mTestMode, val); } } @@ -1153,6 +1184,7 @@ public class PropertyInvalidatedCache<Query, Result> { @Nullable QueryHandler<Query, Result> computer) { mPropertyName = createPropertyName(args.mModule, args.mApi); mCacheName = cacheName; + mCacheNullResults = args.mCacheNulls && Flags.picCacheNulls(); mNonce = getNonceHandler(mPropertyName); mMaxEntries = args.mMaxEntries; mCache = new CacheMap<>(args.mIsolateUids, args.mTestMode); @@ -1491,12 +1523,24 @@ public class PropertyInvalidatedCache<Query, Result> { } return recompute(query); } + + final boolean cacheHit; final Result cachedResult; synchronized (mLock) { if (currentNonce == mLastSeenNonce) { cachedResult = mCache.get(query); - - if (cachedResult != null) mHits++; + if (cachedResult == null) { + if (mCacheNullResults) { + cacheHit = mCache.containsKey(query); + } else { + cacheHit = false; + } + } else { + cacheHit = true; + } + if (cacheHit) { + mHits++; + } } else { if (DEBUG) { Log.d(TAG, formatSimple( @@ -1506,16 +1550,18 @@ public class PropertyInvalidatedCache<Query, Result> { } clear(); mLastSeenNonce = currentNonce; + cacheHit = false; cachedResult = null; } } + // Cache hit --- but we're not quite done yet. A value in the cache might need to // be augmented in a "refresh" operation. The refresh operation can combine the // old and the new nonce values. In order to make sure the new parts of the value // are consistent with the old, possibly-reused parts, we check the property value // again after the refresh and do the whole fetch again if the property invalidated // us while we were refreshing. - if (cachedResult != null) { + if (cacheHit) { final Result refreshedResult = refresh(cachedResult, query); if (refreshedResult != cachedResult) { if (DEBUG) { @@ -1550,6 +1596,7 @@ public class PropertyInvalidatedCache<Query, Result> { } return maybeCheckConsistency(query, cachedResult); } + // Cache miss: make the value from scratch. if (DEBUG) { Log.d(TAG, "cache miss for " + cacheName() + " " + queryToString(query)); @@ -1558,8 +1605,13 @@ public class PropertyInvalidatedCache<Query, Result> { synchronized (mLock) { // If someone else invalidated the cache while we did the recomputation, don't // update the cache with a potentially stale result. - if (mLastSeenNonce == currentNonce && result != null) { - mCache.put(query, result); + if (mLastSeenNonce == currentNonce) { + if (result != null || mCacheNullResults) { + mCache.put(query, result); + } + if (result == null) { + mNulls++; + } } mMisses++; } @@ -1947,10 +1999,12 @@ public class PropertyInvalidatedCache<Query, Result> { } // Return true if this cache has had any activity. If the hits, misses, and skips are all - // zero then the client never tried to use the cache. - private boolean isActive() { + // zero then the client never tried to use the cache. If invalidations and corks are also + // zero then the server never tried to use the cache. + private boolean isActive(NonceHandler.Stats stats) { synchronized (mLock) { - return mHits + mMisses + getSkipsLocked() > 0; + return mHits + mMisses + getSkipsLocked() + + stats.invalidated + stats.corkedInvalidates > 0; } } @@ -1968,15 +2022,15 @@ public class PropertyInvalidatedCache<Query, Result> { NonceHandler.Stats stats = mNonce.getStats(); synchronized (mLock) { - if (brief && !isActive()) { + if (brief && !isActive(stats)) { return; } pw.println(formatSimple(" Cache Name: %s", cacheName())); pw.println(formatSimple(" Property: %s", mPropertyName)); pw.println(formatSimple( - " Hits: %d, Misses: %d, Skips: %d, Clears: %d, Uids: %d", - mHits, mMisses, getSkipsLocked(), mClears, mCache.size())); + " Hits: %d, Misses: %d, Skips: %d, Clears: %d, Nulls: %d", + mHits, mMisses, getSkipsLocked(), mClears, mNulls)); // Print all the skip reasons. pw.format(" Skip-%s: %d", sNonceName[0], mSkips[0]); @@ -1986,7 +2040,7 @@ public class PropertyInvalidatedCache<Query, Result> { pw.println(); pw.println(formatSimple( - " Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d", + " Nonce: 0x%016x, Invalidates: %d, Corked: %d", mLastSeenNonce, stats.invalidated, stats.corkedInvalidates)); pw.println(formatSimple( " Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d", diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index e451116081fa..53a7dad76788 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -17,6 +17,7 @@ package android.app; import static android.app.appfunctions.flags.Flags.enableAppFunctionManager; +import static android.provider.flags.Flags.stageFlagsForBuild; import static android.server.Flags.removeGameManagerServiceFromWear; import android.accounts.AccountManager; @@ -163,6 +164,7 @@ import android.media.tv.tunerresourcemanager.ITunerResourceManager; import android.media.tv.tunerresourcemanager.TunerResourceManager; import android.nearby.NearbyFrameworkInitializer; import android.net.ConnectivityFrameworkInitializer; +import android.net.ConnectivityFrameworkInitializerBaklava; import android.net.ConnectivityFrameworkInitializerTiramisu; import android.net.INetworkPolicyManager; import android.net.IPacProxyManager; @@ -173,7 +175,6 @@ import android.net.NetworkWatchlistManager; import android.net.PacProxyManager; import android.net.TetheringManager; import android.net.VpnManager; -import android.net.vcn.VcnFrameworkInitializer; import android.net.wifi.WifiFrameworkInitializer; import android.net.wifi.nl80211.WifiNl80211Manager; import android.net.wifi.sharedconnectivity.app.SharedConnectivityManager; @@ -190,6 +191,7 @@ import android.os.IBatteryPropertiesRegistrar; import android.os.IBinder; import android.os.IDumpstate; import android.os.IHardwarePropertiesManager; +import android.os.IHintManager; import android.os.IPowerManager; import android.os.IPowerStatsService; import android.os.IRecoverySystem; @@ -215,6 +217,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.Vibrator; import android.os.VibratorManager; +import android.os.flagging.ConfigInfrastructureFrameworkInitializer; import android.os.health.SystemHealthManager; import android.os.image.DynamicSystemManager; import android.os.image.IDynamicSystemService; @@ -238,6 +241,8 @@ import android.security.advancedprotection.AdvancedProtectionManager; import android.security.advancedprotection.IAdvancedProtectionService; import android.security.attestationverification.AttestationVerificationManager; import android.security.attestationverification.IAttestationVerificationManagerService; +import android.security.forensic.ForensicManager; +import android.security.forensic.IForensicService; import android.security.keystore.KeyStoreManager; import android.service.oemlock.IOemLockService; import android.service.oemlock.OemLockManager; @@ -1195,8 +1200,10 @@ public final class SystemServiceRegistry { public SystemHealthManager createService(ContextImpl ctx) throws ServiceNotFoundException { IBinder batteryStats = ServiceManager.getServiceOrThrow(BatteryStats.SERVICE_NAME); IBinder powerStats = ServiceManager.getService(Context.POWER_STATS_SERVICE); + IBinder perfHint = ServiceManager.getService(Context.PERFORMANCE_HINT_SERVICE); return new SystemHealthManager(IBatteryStats.Stub.asInterface(batteryStats), - IPowerStatsService.Stub.asInterface(powerStats)); + IPowerStatsService.Stub.asInterface(powerStats), + IHintManager.Stub.asInterface(perfHint)); }}); registerService(Context.CONTEXTHUB_SERVICE, ContextHubManager.class, @@ -1790,6 +1797,18 @@ public final class SystemServiceRegistry { } }); + registerService(Context.FORENSIC_SERVICE, ForensicManager.class, + new CachedServiceFetcher<ForensicManager>() { + @Override + public ForensicManager createService(ContextImpl ctx) + throws ServiceNotFoundException { + IBinder b = ServiceManager.getServiceOrThrow( + Context.FORENSIC_SERVICE); + IForensicService service = IForensicService.Stub.asInterface(b); + return new ForensicManager(service); + } + }); + sInitializing = true; try { // Note: the following functions need to be @SystemApis, once they become mainline @@ -1818,7 +1837,11 @@ public final class SystemServiceRegistry { OnDevicePersonalizationFrameworkInitializer.registerServiceWrappers(); DeviceLockFrameworkInitializer.registerServiceWrappers(); VirtualizationFrameworkInitializer.registerServiceWrappers(); - VcnFrameworkInitializer.registerServiceWrappers(); + ConnectivityFrameworkInitializerBaklava.registerServiceWrappers(); + + if (stageFlagsForBuild()) { + ConfigInfrastructureFrameworkInitializer.registerServiceWrappers(); + } if (com.android.server.telecom.flags.Flags.telecomMainlineBlockedNumbersManager()) { ProviderFrameworkInitializer.registerServiceWrappers(); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 4e68b5af72d2..e766ae2fce0d 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -16,6 +16,7 @@ package android.app.admin; +import static android.app.admin.flags.Flags.FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; import static android.Manifest.permission.LOCK_DEVICE; @@ -17196,11 +17197,14 @@ public class DevicePolicyManager { * @throws SecurityException if the caller does not hold * {@link android.Manifest.permission#MANAGE_PROFILE_AND_DEVICE_OWNERS}. * @throws ProvisioningException if an error occurred during provisioning. + * @deprecated Use {@link #createManagedProfile} and {@link #finalizeCreateManagedProfile} * @hide */ @Nullable @SystemApi + @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) + @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED) public UserHandle createAndProvisionManagedProfile( @NonNull ManagedProfileProvisioningParams provisioningParams) throws ProvisioningException { @@ -17218,6 +17222,69 @@ public class DevicePolicyManager { } /** + * Creates a managed profile and sets the + * {@link ManagedProfileProvisioningParams#getProfileAdminComponentName()} as the profile + * owner. The method {@link #finalizeCreateManagedProfile} must be called after to finalize the + * creation of the managed profile. + * + * <p>The method {@link #checkProvisioningPrecondition} must return {@link #STATUS_OK} + * before calling this method. If it doesn't, a ProvisioningException will be thrown. + * + * @param provisioningParams Params required to provision a managed profile, + * see {@link ManagedProfileProvisioningParams}. + * @return The {@link UserHandle} of the created profile or {@code null} if the service is + * not available. + * @throws ProvisioningException if an error occurred during provisioning. + * @hide + */ + @Nullable + @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) + @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED) + public UserHandle createManagedProfile( + @NonNull ManagedProfileProvisioningParams provisioningParams) + throws ProvisioningException { + if (mService == null) { + return null; + } + try { + return mService.createManagedProfile(provisioningParams, mContext.getPackageName()); + } catch (ServiceSpecificException e) { + throw new ProvisioningException(e, e.errorCode, getErrorMessage(e)); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Finalizes the creation of a managed profile by informing the necessary components that + * the managed profile is ready. + * + * @param provisioningParams Params required to provision a managed profile, + * see {@link ManagedProfileProvisioningParams}. + * @param managedProfileUser The recently created managed profile. + * @throws ProvisioningException if an error occurred during provisioning. + * @hide + */ + @SuppressLint("UserHandle") + @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) + @FlaggedApi(FLAG_SPLIT_CREATE_MANAGED_PROFILE_ENABLED) + public void finalizeCreateManagedProfile( + @NonNull ManagedProfileProvisioningParams provisioningParams, + @NonNull UserHandle managedProfileUser) + throws ProvisioningException { + if (mService == null) { + return; + } + try { + mService.finalizeCreateManagedProfile(provisioningParams, managedProfileUser); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Removes a manged profile from the device only when called from a managed profile's context * * @param user UserHandle of the profile to be removed diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index fa984af68016..d048b5371fc4 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -570,6 +570,8 @@ interface IDevicePolicyManager { void setOrganizationIdForUser(in String callerPackage, in String enterpriseId, int userId); UserHandle createAndProvisionManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage); + UserHandle createManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in String callerPackage); + void finalizeCreateManagedProfile(in ManagedProfileProvisioningParams provisioningParams, in UserHandle managedProfileUser); void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams, in String callerPackage); void finalizeWorkProfileProvisioning(in UserHandle managedProfileUser, in Account migratedAccount); diff --git a/core/java/android/app/admin/flags/flags.aconfig b/core/java/android/app/admin/flags/flags.aconfig index 404471e266d2..581efa5d2efa 100644 --- a/core/java/android/app/admin/flags/flags.aconfig +++ b/core/java/android/app/admin/flags/flags.aconfig @@ -343,6 +343,16 @@ flag { } flag { + name: "active_admin_cleanup" + namespace: "enterprise" + description: "Remove ActiveAdmin from EnforcingAdmin and related cleanups" + bug: "335663055" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "user_provisioning_same_state" namespace: "enterprise" description: "Handle exceptions while setting same provisioning state." @@ -372,7 +382,7 @@ flag { is_exported: true namespace: "enterprise" description: "Allows DPMS to enable or disable SupervisionService based on whether the device is being managed by the supervision role holder." - bug: "376213673" + bug: "358134581" } flag { diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java index dcac59c19df4..5004c02194ea 100644 --- a/core/java/android/app/backup/BackupTransport.java +++ b/core/java/android/app/backup/BackupTransport.java @@ -16,6 +16,8 @@ package android.app.backup; +import android.annotation.FlaggedApi; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Intent; @@ -27,6 +29,7 @@ import android.os.RemoteException; import com.android.internal.backup.IBackupTransport; import com.android.internal.backup.ITransportStatusCallback; import com.android.internal.infra.AndroidFuture; +import com.android.server.backup.Flags; import java.util.Arrays; import java.util.List; @@ -671,6 +674,22 @@ public class BackupTransport { } /** + * Ask the transport whether packages that are about to be backed up or restored should not be + * put into a restricted mode by the framework and started normally instead. + * + * @param operationType 0 for backup, 1 for restore. + * @return a subset of the {@code packageNames} passed in, indicating + * which packages should NOT be put into restricted mode for the given operation type. + */ + @NonNull + @FlaggedApi(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + public List<String> getPackagesThatShouldNotUseRestrictedMode( + @NonNull List<String> packageNames, + @BackupAnnotations.OperationType int operationType) { + return List.of(); + } + + /** * Bridge between the actual IBackupTransport implementation and the stable API. If the * binder interface needs to change, we use this layer to translate so that we can * (if appropriate) decouple those framework-side changes from the BackupTransport @@ -977,5 +996,19 @@ public class BackupTransport { resultFuture.cancel(/* mayInterruptIfRunning */ true); } } + + @Override + @FlaggedApi(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + public void getPackagesThatShouldNotUseRestrictedMode(List<String> packageNames, + int operationType, AndroidFuture<List<String>> resultFuture) { + try { + List<String> result = + BackupTransport.this.getPackagesThatShouldNotUseRestrictedMode(packageNames, + operationType); + resultFuture.complete(result); + } catch (RuntimeException e) { + resultFuture.cancel(/* mayInterruptIfRunning */ true); + } + } } } diff --git a/core/java/android/app/keyguard.aconfig b/core/java/android/app/keyguard.aconfig new file mode 100644 index 000000000000..9cd1c1579416 --- /dev/null +++ b/core/java/android/app/keyguard.aconfig @@ -0,0 +1,10 @@ +package: "android.app" +container: "system" + +flag { + namespace: "wallet_integration" + name: "device_unlock_listener" + is_exported: true + description: "Enable listener API for device unlock." + bug: "296195355" +}
\ No newline at end of file diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig index a487da297739..2e3d5e15e037 100644 --- a/core/java/android/app/notification.aconfig +++ b/core/java/android/app/notification.aconfig @@ -13,6 +13,13 @@ flag { } flag { + name: "notifications_redesign_templates" + namespace: "systemui" + description: "Notifications Redesign: Update notification templates" + bug: "378660052" +} + +flag { name: "modes_api" is_exported: true namespace: "systemui" diff --git a/core/java/android/app/performance.aconfig b/core/java/android/app/performance.aconfig index 61b53f97fea1..359c84eeb559 100644 --- a/core/java/android/app/performance.aconfig +++ b/core/java/android/app/performance.aconfig @@ -35,3 +35,10 @@ flag { bug: "373752556" } +flag { + namespace: "system_performance" + name: "pic_cache_nulls" + is_fixed_read_only: true + description: "Cache null returns from binder calls" + bug: "372923336" +} diff --git a/services/supervision/java/com/android/server/supervision/SupervisionManagerInternal.java b/core/java/android/app/supervision/SupervisionManagerInternal.java index 5df9dd521092..d571e14ff5fa 100644 --- a/services/supervision/java/com/android/server/supervision/SupervisionManagerInternal.java +++ b/core/java/android/app/supervision/SupervisionManagerInternal.java @@ -14,11 +14,11 @@ * limitations under the License. */ -package com.android.server.supervision; +package android.app.supervision; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.os.Bundle; +import android.os.PersistableBundle; /** * Local system service interface for {@link SupervisionService}. @@ -35,6 +35,11 @@ public abstract class SupervisionManagerInternal { public abstract boolean isSupervisionEnabledForUser(@UserIdInt int userId); /** + * Returns whether the supervision lock screen needs to be shown. + */ + public abstract boolean isSupervisionLockscreenEnabledForUser(@UserIdInt int userId); + + /** * Set whether supervision is enabled for the specified user. * * @param userId The user to set the supervision state for @@ -50,5 +55,5 @@ public abstract class SupervisionManagerInternal { * @param options Optional configuration parameters for the supervision lock screen */ public abstract void setSupervisionLockscreenEnabledForUser( - @UserIdInt int userId, boolean enabled, @Nullable Bundle options); + @UserIdInt int userId, boolean enabled, @Nullable PersistableBundle options); } diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl index 730bb73da3bb..ffa54881cb9d 100644 --- a/core/java/android/app/trust/ITrustManager.aidl +++ b/core/java/android/app/trust/ITrustManager.aidl @@ -18,6 +18,7 @@ package android.app.trust; import android.app.trust.ITrustListener; import android.hardware.biometrics.BiometricSourceType; +import com.android.internal.policy.IDeviceLockedStateListener; /** * System private API to comunicate with trust service. @@ -43,4 +44,8 @@ interface ITrustManager { boolean isActiveUnlockRunning(int userId); @EnforcePermission("ACCESS_FINE_LOCATION") boolean isInSignificantPlace(); + @EnforcePermission("SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE") + void registerDeviceLockedStateListener(in IDeviceLockedStateListener listener, int deviceId); + @EnforcePermission("SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE") + void unregisterDeviceLockedStateListener(in IDeviceLockedStateListener listener); } diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java index 1ef83cdf3f85..8c8970ea5834 100644 --- a/core/java/android/app/trust/TrustManager.java +++ b/core/java/android/app/trust/TrustManager.java @@ -31,6 +31,8 @@ import android.os.Message; import android.os.RemoteException; import android.util.ArrayMap; +import com.android.internal.policy.IDeviceLockedStateListener; + import java.util.ArrayList; import java.util.List; @@ -259,6 +261,35 @@ public class TrustManager { } /** + * Registers a listener for device lock state events. + * + * Requires the {@link android.Manifest.permission#SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE} + * permission. + */ + public void registerDeviceLockedStateListener(final IDeviceLockedStateListener listener, + int deviceId) { + try { + mService.registerDeviceLockedStateListener(listener, deviceId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Unregisters a listener for device lock state events. + * + * Requires the {@link android.Manifest.permission#SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE} + * permission. + */ + public void unregisterDeviceLockedStateListener(final IDeviceLockedStateListener listener) { + try { + mService.unregisterDeviceLockedStateListener(listener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * @return whether {@param userId} has enabled and configured trust agents. Ignores short-term * unavailability of trust due to {@link LockPatternUtils.StrongAuthTracker}. */ diff --git a/core/java/android/appwidget/flags.aconfig b/core/java/android/appwidget/flags.aconfig index ce515761551c..fb33348d9c26 100644 --- a/core/java/android/appwidget/flags.aconfig +++ b/core/java/android/appwidget/flags.aconfig @@ -92,3 +92,13 @@ flag { is_exported: true is_fixed_read_only: true } + +flag { + name: "check_remote_views_uri_permission" + namespace: "app_widgets" + description: "Check that the widget provider has permissions to access any URIs within its RemoteViews" + bug: "369137473" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig index c47fe236faf0..de01280f293f 100644 --- a/core/java/android/companion/virtual/flags/flags.aconfig +++ b/core/java/android/companion/virtual/flags/flags.aconfig @@ -148,6 +148,14 @@ flag { flag { namespace: "virtual_devices" + name: "notifications_for_device_streaming" + description: "Add notifications permissions to device streaming role" + bug: "375240276" + is_exported: true +} + +flag { + namespace: "virtual_devices" name: "default_device_camera_access_policy" description: "API for default device camera access policy" bug: "371173368" diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 3152ff4564fe..37295ac94823 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -193,6 +193,42 @@ public abstract class PackageManager { "android.net.PROPERTY_SELF_CERTIFIED_NETWORK_CAPABILITIES"; /** + * <application> level {@link android.content.pm.PackageManager.Property} tag + * specifying whether the app should be put into the "restricted" backup mode when it's started + * for backup and restore operations. + * + * <p> See <a + * href="https://developer.android.com/identity/data/autobackup#ImplementingBackupAgent"> for + * information about restricted mode</a>. + * + * <p> Starting with Android 16 apps may not be started in restricted mode based on this + * property. + * + * <p><b>Syntax:</b> + * <pre> + * <application> + * <property + * android:name="android.app.backup.PROPERTY_USE_RESTRICTED_BACKUP_MODE" + * android:value="true|false"/> + * </application> + * </pre> + * + * <p>If this property is set, the operating system will respect it for now (see Note below). + * If it's not set, the behavior depends on the SDK level that the app is targeting. For apps + * targeting SDK level {@link android.os.Build.VERSION_CODES#VANILLA_ICE_CREAM} or lower, the + * property defaults to {@code true}. For apps targeting SDK level + * {@link android.os.Build.VERSION_CODES#BAKLAVA} or higher, the operating system will make a + * decision dynamically. + * + * <p>Note: It's not recommended to set this property to {@code true} unless absolutely + * necessary. In a future Android version, this property may be deprecated in favor of removing + * restricted mode completely. + */ + @FlaggedApi(com.android.server.backup.Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + public static final String PROPERTY_USE_RESTRICTED_BACKUP_MODE = + "android.app.backup.PROPERTY_USE_RESTRICTED_BACKUP_MODE"; + + /** * Application level property that an app can specify to opt-out from having private data * directories both on the internal and external storages. * @@ -292,6 +328,10 @@ public abstract class PackageManager { * <p> * The value of a property will only have a single type, as defined by * the property itself. + * + * <p class="note"><strong>Note:</strong> + * In android version {@link Build.VERSION_CODES#VANILLA_ICE_CREAM} and earlier, + * the {@code equals} and {@code hashCode} methods for this class may not function as expected. */ public static final class Property implements Parcelable { private static final int TYPE_BOOLEAN = 1; @@ -523,6 +563,40 @@ public abstract class PackageManager { return new Property[size]; } }; + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Property)) { + return false; + } + final Property property = (Property) obj; + return mType == property.mType && + Objects.equals(mName, property.mName) && + Objects.equals(mClassName, property.mClassName) && + Objects.equals(mPackageName, property.mPackageName) && + (mType == TYPE_BOOLEAN ? mBooleanValue == property.mBooleanValue : + mType == TYPE_FLOAT ? Float.compare(mFloatValue, property.mFloatValue) == 0 : + mType == TYPE_INTEGER ? mIntegerValue == property.mIntegerValue : + mType == TYPE_RESOURCE ? mIntegerValue == property.mIntegerValue : + mStringValue.equals(property.mStringValue)); + } + + @Override + public int hashCode() { + int result = Objects.hash(mName, mType, mClassName, mPackageName); + if (mType == TYPE_BOOLEAN) { + result = 31 * result + (mBooleanValue ? 1 : 0); + } else if (mType == TYPE_FLOAT) { + result = 31 * result + Float.floatToIntBits(mFloatValue); + } else if (mType == TYPE_INTEGER) { + result = 31 * result + mIntegerValue; + } else if (mType == TYPE_RESOURCE) { + result = 31 * result + mIntegerValue; + } else if (mType == TYPE_STRING) { + result = 31 * result + mStringValue.hashCode(); + } + return result; + } } /** diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java index f7191e605fb8..5dfec9809f6e 100644 --- a/core/java/android/content/pm/SharedLibraryInfo.java +++ b/core/java/android/content/pm/SharedLibraryInfo.java @@ -105,6 +105,8 @@ public final class SharedLibraryInfo implements Parcelable { private final List<VersionedPackage> mOptionalDependentPackages; private List<SharedLibraryInfo> mDependencies; + private final List<String> mCertDigests; + /** * Creates a new instance. * @@ -134,6 +136,7 @@ public final class SharedLibraryInfo implements Parcelable { mDependencies = dependencies; mIsNative = isNative; mOptionalDependentPackages = null; + mCertDigests = null; } /** @@ -165,6 +168,7 @@ public final class SharedLibraryInfo implements Parcelable { mDeclaringPackage = declaringPackage; mDependencies = dependencies; mIsNative = isNative; + mCertDigests = null; var allDependents = allDependentPackages.first; var usesLibOptional = allDependentPackages.second; @@ -206,6 +210,7 @@ public final class SharedLibraryInfo implements Parcelable { mIsNative = parcel.readBoolean(); mOptionalDependentPackages = parcel.readParcelableList(new ArrayList<>(), VersionedPackage.class.getClassLoader(), VersionedPackage.class); + mCertDigests = parcel.createStringArrayList(); } /** @@ -214,6 +219,29 @@ public final class SharedLibraryInfo implements Parcelable { * @param versionMajor */ public SharedLibraryInfo(String name, long versionMajor, int type) { + //TODO: change to this(name, versionMajor, type, /* certDigest= */null); after flag removal + mPath = null; + mPackageName = null; + mName = name; + mVersion = versionMajor; + mType = type; + mDeclaringPackage = null; + mDependentPackages = null; + mDependencies = null; + mIsNative = false; + mOptionalDependentPackages = null; + mCertDigests = null; + } + + /** + * @hide + * @param name The lib name. + * @param versionMajor The lib major version. + * @param type The type of shared library. + * @param certDigests The list of certificate digests for this shared library. + */ + @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER) + public SharedLibraryInfo(String name, long versionMajor, int type, List<String> certDigests) { mPath = null; mPackageName = null; mName = name; @@ -224,6 +252,7 @@ public final class SharedLibraryInfo implements Parcelable { mDependencies = null; mIsNative = false; mOptionalDependentPackages = null; + mCertDigests = certDigests; } /** @@ -433,6 +462,19 @@ public final class SharedLibraryInfo implements Parcelable { return mOptionalDependentPackages; } + /** + * Gets the list of certificate digests for the shared library. + * + * @return The list of certificate digests + */ + @FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER) + public @NonNull List<String> getCertDigests() { + if (mCertDigests == null) { + return Collections.emptyList(); + } + return mCertDigests; + } + @Override public int describeContents() { return 0; @@ -463,6 +505,7 @@ public final class SharedLibraryInfo implements Parcelable { parcel.writeTypedList(mDependencies); parcel.writeBoolean(mIsNative); parcel.writeParcelableList(mOptionalDependentPackages, flags); + parcel.writeStringList(mCertDigests); } private static String typeToString(int type) { diff --git a/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl new file mode 100644 index 000000000000..06fcabcf55e9 --- /dev/null +++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.aidl @@ -0,0 +1,19 @@ +/** + * 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 android.content.pm.dependencyinstaller; + +parcelable DependencyInstallerCallback;
\ No newline at end of file diff --git a/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java new file mode 100644 index 000000000000..ba089f7fd33e --- /dev/null +++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerCallback.java @@ -0,0 +1,100 @@ +/** + * 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 android.content.pm.dependencyinstaller; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.content.pm.Flags; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.RemoteException; + +/** + * Callbacks for {@link DependencyInstallerService}. The implementation of + * DependencyInstallerService uses this interface to indicate completion of the session creation + * request given by the system server. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER) +public final class DependencyInstallerCallback implements Parcelable { + private final IBinder mBinder; + private final IDependencyInstallerCallback mCallback; + + /** @hide */ + public DependencyInstallerCallback(IBinder binder) { + mBinder = binder; + mCallback = IDependencyInstallerCallback.Stub.asInterface(binder); + } + + private DependencyInstallerCallback(Parcel in) { + mBinder = in.readStrongBinder(); + mCallback = IDependencyInstallerCallback.Stub.asInterface(mBinder); + } + + /** + * Callback to indicate that all the requested dependencies have been resolved and their + * sessions created. See {@link DependencyInstallerService#onDependenciesRequired}. + * + * @param sessionIds the install session IDs for all requested dependencies + */ + public void onAllDependenciesResolved(@NonNull int[] sessionIds) { + try { + mCallback.onAllDependenciesResolved(sessionIds); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Callback to indicate that at least one of the required dependencies could not be resolved + * and any associated sessions have been abandoned. + */ + public void onFailureToResolveAllDependencies() { + try { + mCallback.onFailureToResolveAllDependencies(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeStrongBinder(mBinder); + } + + public static final @NonNull Creator<DependencyInstallerCallback> CREATOR = + new Creator<>() { + @Override + public DependencyInstallerCallback createFromParcel(Parcel in) { + return new DependencyInstallerCallback(in); + } + + @Override + public DependencyInstallerCallback[] newArray(int size) { + return new DependencyInstallerCallback[size]; + } + }; +} diff --git a/core/java/android/content/pm/dependencyinstaller/DependencyInstallerService.java b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerService.java new file mode 100644 index 000000000000..11864150e072 --- /dev/null +++ b/core/java/android/content/pm/dependencyinstaller/DependencyInstallerService.java @@ -0,0 +1,83 @@ +/** + * 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 android.content.pm.dependencyinstaller; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.content.pm.Flags; +import android.content.pm.SharedLibraryInfo; +import android.os.IBinder; + +import java.util.List; + +/** + * Service that needs to be implemented by the holder of the DependencyInstaller role. This service + * will be invoked by the system during application installations if it depends on + * {@link android.content.pm.SharedLibraryInfo#TYPE_STATIC} or + * {@link android.content.pm.SharedLibraryInfo#TYPE_SDK_PACKAGE} and those dependencies aren't + * already installed. + * <p> + * Below is an example manifest registration for a {@code DependencyInstallerService}. + * <pre> + * {@code + * <service android:name=".ExampleDependencyInstallerService" + * android:permission="android.permission.BIND_DEPENDENCY_INSTALLER" > + * ... + * <intent-filter> + * <action android:name="android.content.pm.action.INSTALL_DEPENDENCY" /> + * </intent-filter> + * </service> + * } + * </pre> + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_SDK_DEPENDENCY_INSTALLER) +public abstract class DependencyInstallerService extends Service { + + private IDependencyInstallerService mBinder; + + @Override + public final @NonNull IBinder onBind(@Nullable Intent intent) { + if (mBinder == null) { + mBinder = new IDependencyInstallerService.Stub() { + @Override + public void onDependenciesRequired(List<SharedLibraryInfo> neededLibraries, + DependencyInstallerCallback callback) { + DependencyInstallerService.this.onDependenciesRequired(neededLibraries, + callback); + } + }; + } + return mBinder.asBinder(); + } + + /** + * Notify the holder of the DependencyInstaller role of the missing dependencies required for + * the completion of an active install session. + * + * @param neededLibraries the list of shared library dependencies needed to be obtained and + * installed. + */ + public abstract void onDependenciesRequired(@NonNull List<SharedLibraryInfo> neededLibraries, + @NonNull DependencyInstallerCallback callback); +} diff --git a/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl new file mode 100644 index 000000000000..92d1d9e118e6 --- /dev/null +++ b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerCallback.aidl @@ -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 android.content.pm.dependencyinstaller; + +import java.util.List; + +/** +* Callbacks for Dependency Installer. The app side invokes on this interface to indicate +* completion of the async dependency install request given by the system server. +* +* {@hide} +*/ +oneway interface IDependencyInstallerCallback { + /** + * Callback to indicate that all the requested dependencies have been resolved and have been + * committed for installation. See {@link DependencyInstallerService#onDependenciesRequired}. + * + * @param sessionIds the install session IDs for all requested dependencies + */ + void onAllDependenciesResolved(in int[] sessionIds); + + /** + * Callback to indicate that at least one of the required dependencies could not be resolved + * and any associated sessions have been abandoned. + */ + void onFailureToResolveAllDependencies(); +}
\ No newline at end of file diff --git a/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerService.aidl b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerService.aidl new file mode 100644 index 000000000000..94f5bf45ca9c --- /dev/null +++ b/core/java/android/content/pm/dependencyinstaller/IDependencyInstallerService.aidl @@ -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 android.content.pm.dependencyinstaller; + +import android.content.pm.dependencyinstaller.DependencyInstallerCallback; +import android.content.pm.SharedLibraryInfo; +import java.util.List; + +/** +* Interface used to communicate with the application code that holds the Dependency Installer role. +* {@hide} +*/ +oneway interface IDependencyInstallerService { + /** + * Notify dependency installer of the required dependencies to complete the current install + * session. + * + * @param neededLibraries the list of shared library dependencies needed to be obtained and + * installed. + */ + void onDependenciesRequired(in List<SharedLibraryInfo> neededLibraries, + in DependencyInstallerCallback callback); + }
\ 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 9ba5a352358b..e181ae8ef3c7 100644 --- a/core/java/android/content/pm/flags.aconfig +++ b/core/java/android/content/pm/flags.aconfig @@ -366,3 +366,13 @@ flag { description: "Block app installations that specify an incompatible minor SDK version" bug: "377474232" } + +flag { + name: "app_compat_option_16kb" + is_exported: true + namespace: "devoptions_settings" + description: "Feature flag to enable page size app compat mode from manifest, package manager and settings level." + bug: "371049373" + is_fixed_read_only: true +} + diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java index e9e8578af787..05c8f31df5d6 100644 --- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java +++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java @@ -537,6 +537,9 @@ public class ApkLiteParseUtils { hasBindDeviceAdminPermission); break; case TAG_USES_SDK_LIBRARY: + if (!android.content.pm.Flags.sdkDependencyInstaller()) { + break; + } String usesSdkLibName = parser.getAttributeValue( ANDROID_RES_NAMESPACE, "name"); long usesSdkLibVersionMajor = parser.getAttributeIntValue( diff --git a/core/java/android/hardware/DisplayLuts.java b/core/java/android/hardware/DisplayLuts.java index b162ad6e2d15..6343ba19f569 100644 --- a/core/java/android/hardware/DisplayLuts.java +++ b/core/java/android/hardware/DisplayLuts.java @@ -16,116 +16,294 @@ package android.hardware; +import android.annotation.FlaggedApi; import android.annotation.NonNull; +import android.hardware.flags.Flags; import android.util.IntArray; import java.util.ArrayList; -import java.util.List; /** - * @hide + * DisplayLuts provides the developers to apply Lookup Tables (Luts) to a + * {@link android.view.SurfaceControl}. Luts provides ways to control tonemapping + * for specific content. + * + * The general flow is as follows: + * <p> + * <img src="{@docRoot}reference/android/images/graphics/DisplayLuts.png" /> + * <figcaption style="text-align: center;">DisplayLuts flow</figcaption> + * </p> + * + * @see LutProperties */ +@FlaggedApi(Flags.FLAG_LUTS_API) public final class DisplayLuts { + private ArrayList<Entry> mEntries; private IntArray mOffsets; private int mTotalLength; - private List<float[]> mLutBuffers; - private IntArray mLutDimensions; - private IntArray mLutSizes; - private IntArray mLutSamplingKeys; - private static final int LUT_LENGTH_LIMIT = 100000; - + /** + * Create a {@link DisplayLuts} instance. + */ + @FlaggedApi(Flags.FLAG_LUTS_API) public DisplayLuts() { + mEntries = new ArrayList<>(); mOffsets = new IntArray(); mTotalLength = 0; - - mLutBuffers = new ArrayList<>(); - mLutDimensions = new IntArray(); - mLutSizes = new IntArray(); - mLutSamplingKeys = new IntArray(); } - /** - * Add the lut to be applied. - * - * @param buffer - * @param dimension either 1D or 3D - * @param size - * @param samplingKey - */ - public void addLut(@NonNull float[] buffer, @LutProperties.Dimension int dimension, - int size, @LutProperties.SamplingKey int samplingKey) { + @FlaggedApi(Flags.FLAG_LUTS_API) + public static class Entry { + private float[] mBuffer; + private @LutProperties.Dimension int mDimension; + private int mSize; + private @LutProperties.SamplingKey int mSamplingKey; + + private static final int LUT_LENGTH_LIMIT = 100000; + + /** + * Create a Lut entry. + * + * <p> + * Noted that 1D Lut(s) are treated as gain curves. + * For 3D Lut(s), 3D Lut(s) are used for direct color manipulations. + * The values of 3D Lut(s) data should be normalized to the range {@code 0.0} + * to {@code 1.0}, inclusive. And 3D Lut(s) data is organized in the order of + * R, G, B channels. + * + * @param buffer The raw lut data + * @param dimension Either 1D or 3D + * @param samplingKey The sampling kay used for the Lut + */ + @FlaggedApi(Flags.FLAG_LUTS_API) + public Entry(@NonNull float[] buffer, + @LutProperties.Dimension int dimension, + @LutProperties.SamplingKey int samplingKey) { + if (buffer == null || buffer.length < 1) { + throw new IllegalArgumentException("The buffer cannot be empty!"); + } + + if (buffer.length >= LUT_LENGTH_LIMIT) { + throw new IllegalArgumentException("The lut length is too big to handle!"); + } + + if (dimension != LutProperties.ONE_DIMENSION + && dimension != LutProperties.THREE_DIMENSION) { + throw new IllegalArgumentException("The dimension should be either 1D or 3D!"); + } + + if (dimension == LutProperties.THREE_DIMENSION) { + if (buffer.length <= 3) { + throw new IllegalArgumentException( + "The 3d lut size of each dimension should be over 1!"); + } + int lengthPerChannel = buffer.length; + if (lengthPerChannel % 3 != 0) { + throw new IllegalArgumentException( + "The lut buffer of 3dlut should have 3 channels!"); + } + lengthPerChannel /= 3; - int lutLength = 0; - if (dimension == LutProperties.ONE_DIMENSION) { - lutLength = size; - } else if (dimension == LutProperties.THREE_DIMENSION) { - lutLength = size * size * size; - } else { - clear(); - throw new IllegalArgumentException("The dimension is either 1D or 3D!"); + double size = Math.cbrt(lengthPerChannel); + if (size == (int) size) { + mSize = (int) size; + } else { + throw new IllegalArgumentException( + "Cannot get the cube root of the 3d lut buffer!"); + } + } else { + mSize = buffer.length; + } + + mBuffer = buffer; + mDimension = dimension; + mSamplingKey = samplingKey; } - if (lutLength >= LUT_LENGTH_LIMIT) { - clear(); - throw new IllegalArgumentException("The lut length is too big to handle!"); + /** + * @return the dimension of the lut entry + */ + @FlaggedApi(Flags.FLAG_LUTS_API) + public int getDimension() { + return mDimension; } - mOffsets.add(mTotalLength); - mTotalLength += lutLength; + /** + * @return the size of the lut for each dimension + * @hide + */ + public int getSize() { + return mSize; + } + + /** + * @return the lut raw data of the lut + */ + @FlaggedApi(Flags.FLAG_LUTS_API) + public @NonNull float[] getBuffer() { + return mBuffer; + } + + /** + * @return the sampling key used by the lut + */ + @FlaggedApi(Flags.FLAG_LUTS_API) + public int getSamplingKey() { + return mSamplingKey; + } + + @Override + public String toString() { + return "Entry{" + + "dimension=" + DisplayLuts.Entry.dimensionToString(getDimension()) + + ", size(each dimension)=" + getSize() + + ", samplingKey=" + samplingKeyToString(getSamplingKey()) + "}"; + } + + private static String dimensionToString(int dimension) { + switch(dimension) { + case LutProperties.ONE_DIMENSION: + return "ONE_DIMENSION"; + case LutProperties.THREE_DIMENSION: + return "THREE_DIMENSION"; + default: + return ""; + } + } + + private static String samplingKeyToString(int key) { + switch(key) { + case LutProperties.SAMPLING_KEY_RGB: + return "SAMPLING_KEY_RGB"; + case LutProperties.SAMPLING_KEY_MAX_RGB: + return "SAMPLING_KEY_MAX_RGB"; + default: + return ""; + } + } + } - mLutBuffers.add(buffer); - mLutDimensions.add(dimension); - mLutSizes.add(size); - mLutSamplingKeys.add(samplingKey); + @Override + public String toString() { + StringBuilder sb = new StringBuilder("DisplayLuts{"); + sb.append("\n"); + for (DisplayLuts.Entry entry: mEntries) { + sb.append(entry.toString()); + sb.append("\n"); + } + sb.append("}"); + return sb.toString(); + } + + private void addEntry(Entry entry) { + mEntries.add(entry); + mOffsets.add(mTotalLength); + mTotalLength += entry.getBuffer().length; } private void clear() { - mTotalLength = 0; mOffsets.clear(); - mLutBuffers.clear(); - mLutDimensions.clear(); - mLutSamplingKeys.clear(); + mTotalLength = 0; + mEntries.clear(); + } + + /** + * Set a Lut to be applied. + * + * <p>Use either this or {@link #set(Entry, Entry)}. The function will + * replace any previously set lut(s).</p> + * + * @param entry Either an 1D Lut or a 3D Lut + */ + @FlaggedApi(Flags.FLAG_LUTS_API) + public void set(@NonNull Entry entry) { + if (entry == null) { + throw new IllegalArgumentException("The entry is null!"); + } + clear(); + addEntry(entry); + } + + /** + * Set Luts in order to be applied. + * + * <p> An 1D Lut and 3D Lut will be applied in order. Use either this or + * {@link #set(Entry)}. The function will replace any previously set lut(s)</p> + * + * @param first An 1D Lut + * @param second A 3D Lut + */ + @FlaggedApi(Flags.FLAG_LUTS_API) + public void set(@NonNull Entry first, @NonNull Entry second) { + if (first == null || second == null) { + throw new IllegalArgumentException("The entry is null!"); + } + if (first.getDimension() != LutProperties.ONE_DIMENSION + || second.getDimension() != LutProperties.THREE_DIMENSION) { + throw new IllegalArgumentException("The entries should be 1D and 3D in order!"); + } + clear(); + addEntry(first); + addEntry(second); } /** - * @return the array of Lut buffers + * @hide + */ + public boolean valid() { + return mEntries.size() > 0; + } + + /** + * @hide */ public float[] getLutBuffers() { float[] buffer = new float[mTotalLength]; - for (int i = 0; i < mLutBuffers.size(); i++) { - float[] lutBuffer = mLutBuffers.get(i); + for (int i = 0; i < mEntries.size(); i++) { + float[] lutBuffer = mEntries.get(i).getBuffer(); System.arraycopy(lutBuffer, 0, buffer, mOffsets.get(i), lutBuffer.length); } return buffer; } /** - * @return the starting point of each lut memory region of the lut buffer + * @hide */ public int[] getOffsets() { return mOffsets.toArray(); } /** - * @return the array of Lut size + * @hide */ public int[] getLutSizes() { - return mLutSizes.toArray(); + int[] sizes = new int[mEntries.size()]; + for (int i = 0; i < mEntries.size(); i++) { + sizes[i] = mEntries.get(i).getSize(); + } + return sizes; } /** - * @return the array of Lut dimension + * @hide */ public int[] getLutDimensions() { - return mLutDimensions.toArray(); + int[] dimensions = new int[mEntries.size()]; + for (int i = 0; i < mEntries.size(); i++) { + dimensions[i] = mEntries.get(i).getDimension(); + } + return dimensions; } /** - * @return the array of sampling key + * @hide */ public int[] getLutSamplingKeys() { - return mLutSamplingKeys.toArray(); + int[] samplingKeys = new int[mEntries.size()]; + for (int i = 0; i < mEntries.size(); i++) { + samplingKeys[i] = mEntries.get(i).getSamplingKey(); + } + return samplingKeys; } } diff --git a/core/java/android/hardware/LutProperties.java b/core/java/android/hardware/LutProperties.java index c9c6d6d08ed2..bf40a415b0f7 100644 --- a/core/java/android/hardware/LutProperties.java +++ b/core/java/android/hardware/LutProperties.java @@ -16,23 +16,31 @@ package android.hardware; +import android.annotation.FlaggedApi; import android.annotation.IntDef; +import android.annotation.NonNull; +import android.hardware.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * Lut properties class. + * Provides Lut properties of the device. * - * A Lut (Look-Up Table) is a pre-calculated table for color transformation. - * - * @hide + * <p> + * A Lut (Look-Up Table) is a pre-calculated table for color correction. + * Applications may be interested in the Lut properties exposed by + * this class to determine if the Lut(s) they select using + * {@link android.view.SurfaceControl.Transaction#setLuts} are by the HWC. + * </p> */ +@FlaggedApi(Flags.FLAG_LUTS_API) public final class LutProperties { private final @Dimension int mDimension; private final int mSize; private final @SamplingKey int[] mSamplingKeys; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"SAMPLING_KEY_"}, value = { SAMPLING_KEY_RGB, @@ -42,11 +50,14 @@ public final class LutProperties { } /** use r,g,b channel as the gain value of a Lut */ + @FlaggedApi(Flags.FLAG_LUTS_API) public static final int SAMPLING_KEY_RGB = 0; /** use max of r,g,b channel as the gain value of a Lut */ + @FlaggedApi(Flags.FLAG_LUTS_API) public static final int SAMPLING_KEY_MAX_RGB = 1; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef(value = { ONE_DIMENSION, @@ -56,18 +67,22 @@ public final class LutProperties { } /** The Lut is one dimensional */ + @FlaggedApi(Flags.FLAG_LUTS_API) public static final int ONE_DIMENSION = 1; /** The Lut is three dimensional */ + @FlaggedApi(Flags.FLAG_LUTS_API) public static final int THREE_DIMENSION = 3; + @FlaggedApi(Flags.FLAG_LUTS_API) public @Dimension int getDimension() { return mDimension; } /** - * @return the size of the Lut. + * @return the size of the Lut for each dimension */ + @FlaggedApi(Flags.FLAG_LUTS_API) public int getSize() { return mSize; } @@ -75,6 +90,8 @@ public final class LutProperties { /** * @return the list of sampling keys */ + @FlaggedApi(Flags.FLAG_LUTS_API) + @NonNull public @SamplingKey int[] getSamplingKeys() { if (mSamplingKeys.length == 0) { throw new IllegalStateException("no sampling key!"); diff --git a/core/java/android/hardware/OverlayProperties.java b/core/java/android/hardware/OverlayProperties.java index 24cfc1b53e00..d42bfae23d2b 100644 --- a/core/java/android/hardware/OverlayProperties.java +++ b/core/java/android/hardware/OverlayProperties.java @@ -18,6 +18,7 @@ package android.hardware; import android.annotation.FlaggedApi; import android.annotation.NonNull; +import android.annotation.SuppressLint; import android.hardware.flags.Flags; import android.os.Parcel; import android.os.Parcelable; @@ -72,9 +73,11 @@ public final class OverlayProperties implements Parcelable { } /** - * Gets the lut properties of the display. - * @hide + * Returns the lut properties of the device. */ + @FlaggedApi(Flags.FLAG_LUTS_API) + @SuppressLint("ArrayReturn") + @NonNull public LutProperties[] getLutProperties() { if (mNativeObject == 0) { return null; diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index 58e524e741b3..5533a640b9d8 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -19,9 +19,9 @@ package android.hardware.camera2; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.camera2.impl.CameraMetadataNative; -import android.hardware.camera2.impl.ExtensionKey; import android.hardware.camera2.impl.PublicKey; import android.hardware.camera2.impl.SyntheticKey; import android.hardware.camera2.params.DeviceStateSensorOrientationMap; @@ -6172,6 +6172,66 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION = new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.jpegr.availableJpegRStallDurationsMaximumResolution", android.hardware.camera2.params.StreamConfigurationDuration[].class); + /** + * <p>Color space used for shared session configuration for all the output targets + * when camera is opened in shared mode. This should be one of the values specified in + * availableColorSpaceProfilesMap.</p> + * <p><b>Possible values:</b></p> + * <ul> + * <li>{@link #SHARED_SESSION_COLOR_SPACE_UNSPECIFIED UNSPECIFIED}</li> + * <li>{@link #SHARED_SESSION_COLOR_SPACE_SRGB SRGB}</li> + * <li>{@link #SHARED_SESSION_COLOR_SPACE_DISPLAY_P3 DISPLAY_P3}</li> + * <li>{@link #SHARED_SESSION_COLOR_SPACE_BT2020_HLG BT2020_HLG}</li> + * </ul> + * + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * @see #SHARED_SESSION_COLOR_SPACE_UNSPECIFIED + * @see #SHARED_SESSION_COLOR_SPACE_SRGB + * @see #SHARED_SESSION_COLOR_SPACE_DISPLAY_P3 + * @see #SHARED_SESSION_COLOR_SPACE_BT2020_HLG + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public static final Key<Integer> SHARED_SESSION_COLOR_SPACE = + new Key<Integer>("android.sharedSession.colorSpace", int.class); + + /** + * <p>List of shared output configurations that this camera device supports when + * camera is opened in shared mode. Array contains following entries for each supported + * shared configuration: + * 1) surface type + * 2) width + * 3) height + * 4) format + * 5) mirrorMode + * 6) useReadoutTimestamp + * 7) timestampBase + * 8) dataspace + * 9) usage + * 10) streamUsecase + * 11) physical camera id len + * 12) physical camera id as UTF-8 null terminated string.</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public static final Key<long[]> SHARED_SESSION_OUTPUT_CONFIGURATIONS = + new Key<long[]>("android.sharedSession.outputConfigurations", long[].class); + + /** + * <p>The available stream configurations that this camera device supports for + * shared capture session when camera is opened in shared mode. Android camera framework + * will generate this tag if the camera device can be opened in shared mode.</p> + * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> + * @hide + */ + @SystemApi + @NonNull + @SyntheticKey + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public static final Key<android.hardware.camera2.params.SharedSessionConfiguration> SHARED_SESSION_CONFIGURATION = + new Key<android.hardware.camera2.params.SharedSessionConfiguration>("android.sharedSession.configuration", android.hardware.camera2.params.SharedSessionConfiguration.class); + /** * Mapping from INFO_SESSION_CONFIGURATION_QUERY_VERSION to session characteristics key. diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index fb381d97adc3..852f04793f15 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -446,6 +446,17 @@ public abstract class CameraDevice implements AutoCloseable { public static final int SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED = 1; // ICameraDeviceUser.CONSTRAINED_HIGH_SPEED_MODE; + /** + * Shared camera operation mode. + * + * @see #CameraSharedCaptureSession + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public static final int SESSION_OPERATION_MODE_SHARED = + 2; // ICameraDeviceUser.SHARED_MODE; + /** * First vendor-specific operating mode * @@ -461,6 +472,7 @@ public abstract class CameraDevice implements AutoCloseable { @IntDef(prefix = {"SESSION_OPERATION_MODE"}, value = {SESSION_OPERATION_MODE_NORMAL, SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED, + SESSION_OPERATION_MODE_SHARED, SESSION_OPERATION_MODE_VENDOR_START}) public @interface SessionOperatingMode {}; @@ -1240,7 +1252,6 @@ public abstract class CameraDevice implements AutoCloseable { * * </ul> * - * * @param config A session configuration (see {@link SessionConfiguration}). * * @throws IllegalArgumentException In case the session configuration is invalid; or the output @@ -1559,6 +1570,48 @@ public abstract class CameraDevice implements AutoCloseable { public abstract void onOpened(@NonNull CameraDevice camera); // Must implement /** + * The method called when a camera device has finished opening in shared mode, + * where there can be more than one client accessing the same camera. + * + * <p>At this point, the camera device is ready to use, and + * {@link CameraDevice#createCaptureSession} can be called to set up the shared capture + * session.</p> + * + * @param camera the camera device that has become opened + * @param isPrimaryClient true if the client opening the camera is currently the primary + * client. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public void onOpenedInSharedMode(@NonNull CameraDevice camera, boolean isPrimaryClient) { + // Default empty implementation + } + + /** + * The method called when client access priorities have changed for a camera device opened + * in shared mode where there can be more than one client accessing the same camera. + * + * If the client priority changed from secondary to primary, then it can now + * create capture request and change the capture request parameters. If client priority + * changed from primary to secondary, that implies that a higher priority client has also + * opened the camera in shared mode and the new client is now a primary client + * + * @param camera the camera device whose access priorities have changed. + * @param isPrimaryClient true if the client is now the primary client. + * false if another higher priority client also opened the + * camera and is now the new primary client and this client is + * now a secondary client. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public void onClientSharedAccessPriorityChanged(@NonNull CameraDevice camera, + boolean isPrimaryClient) { + // Default empty implementation + } + + /** * The method called when a camera device has been closed with * {@link CameraDevice#close}. * diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index 75e20582b7b4..266efb7b759c 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -976,6 +976,46 @@ public final class CameraManager { } /** + * Checks if a camera device can be opened in a shared mode for a given {@code cameraId}. + * If this method returns false for a {@code cameraId}, calling {@link #openSharedCamera} + * for that {@code cameraId} will throw an {@link UnsupportedOperationException}. + * + * @param cameraId The unique identifier of the camera device for which sharing support is + * being queried. This identifier must be present in + * {@link #getCameraIdList()}. + * + * @return {@code true} if camera can be opened in shared mode + * for the provided {@code cameraId}; {@code false} otherwise. + * + * @throws IllegalArgumentException If {@code cameraId} is null, or if {@code cameraId} does not + * match any device in {@link #getCameraIdList()}. + * @throws CameraAccessException if the camera device has been disconnected. + * + * @see #getCameraIdList() + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + @SystemApi + public boolean isCameraDeviceSharingSupported(@NonNull String cameraId) + throws CameraAccessException { + if (cameraId == null) { + throw new IllegalArgumentException("Camera ID was null"); + } + + if (CameraManagerGlobal.sCameraServiceDisabled + || !Arrays.asList(CameraManagerGlobal.get().getCameraIdList(mContext.getDeviceId(), + getDevicePolicyFromContext(mContext))).contains(cameraId)) { + throw new IllegalArgumentException( + "Camera ID '" + cameraId + "' not available on device."); + } + + CameraCharacteristics chars = getCameraCharacteristics(cameraId); + long[] sharedOutputConfiguration = + chars.get(CameraCharacteristics.SHARED_SESSION_OUTPUT_CONFIGURATIONS); + return (sharedOutputConfiguration != null); + } + + /** * Retrieves the AttributionSourceState to pass to the CameraService. * * @param deviceIdOverride An override of the AttributionSource's deviceId, if not equal to @@ -1036,6 +1076,9 @@ public final class CameraManager { * @param cameraId The unique identifier of the camera device to open * @param callback The callback for the camera. Must not be null. * @param executor The executor to invoke the callback with. Must not be null. + * @param oomScoreOffset The minimum oom score that cameraservice must see for this client. + * @param rotationOverride The type of rotation override. + * @param sharedMode Parameter specifying if the camera should be opened in shared mode. * * @throws CameraAccessException if the camera is disabled by device policy, * too many camera devices are already open, or the cameraId does not match @@ -1051,7 +1094,8 @@ public final class CameraManager { */ private CameraDevice openCameraDeviceUserAsync(String cameraId, CameraDevice.StateCallback callback, Executor executor, - final int oomScoreOffset, int rotationOverride) throws CameraAccessException { + final int oomScoreOffset, int rotationOverride, boolean sharedMode) + throws CameraAccessException { CameraCharacteristics characteristics = getCameraCharacteristics(cameraId); CameraDevice device = null; synchronized (mLock) { @@ -1070,7 +1114,7 @@ public final class CameraManager { characteristics, this, mContext.getApplicationInfo().targetSdkVersion, - mContext, cameraDeviceSetup); + mContext, cameraDeviceSetup, sharedMode); ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks(); try { @@ -1091,7 +1135,7 @@ public final class CameraManager { mContext.getApplicationInfo().targetSdkVersion, rotationOverride, clientAttribution, - getDevicePolicyFromContext(mContext)); + getDevicePolicyFromContext(mContext), sharedMode); } catch (ServiceSpecificException e) { if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) { throw new AssertionError("Should've gone down the shim path"); @@ -1218,7 +1262,8 @@ public final class CameraManager { @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler) throws CameraAccessException { - openCameraImpl(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler)); + openCameraImpl(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler), + /*oomScoreOffset*/0, getRotationOverride(mContext), /*sharedMode*/false); } /** @@ -1258,7 +1303,7 @@ public final class CameraManager { /*oomScoreOffset*/0, overrideToPortrait ? ICameraService.ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT - : ICameraService.ROTATION_OVERRIDE_NONE); + : ICameraService.ROTATION_OVERRIDE_NONE, /*sharedMode*/false); } /** @@ -1303,9 +1348,56 @@ public final class CameraManager { if (executor == null) { throw new IllegalArgumentException("executor was null"); } - openCameraImpl(cameraId, callback, executor); + openCameraImpl(cameraId, callback, executor, /*oomScoreOffset*/0, + getRotationOverride(mContext), /*sharedMode*/false); + } + + /** + * Opens a shared connection to a camera with the given ID. + * + * <p>The behavior of this method matches that of + * {@link #openCamera(String, Executor, StateCallback)}, except that it opens the camera in + * shared mode where more than one client can access the camera at the same time.</p> + * + * @param cameraId The unique identifier of the camera device to open. + * @param executor The executor which will be used when invoking the callback. + * @param callback The callback which is invoked once the camera is opened + * + * @throws CameraAccessException if the camera is disabled by device policy, or is being used + * by a higher-priority client in non-shared mode or the device + * has reached its maximal resource and cannot open this camera + * device. + * + * @throws IllegalArgumentException if cameraId, the callback or the executor was null, + * or the cameraId does not match any currently or previously + * available camera device. + * + * @throws SecurityException if the application does not have permission to + * access the camera + * + * @see #getCameraIdList + * @see android.app.admin.DevicePolicyManager#setCameraDisabled + * + * @hide + */ + @SystemApi + @RequiresPermission(allOf = { + android.Manifest.permission.SYSTEM_CAMERA, + android.Manifest.permission.CAMERA, + }) + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public void openSharedCamera(@NonNull String cameraId, + @NonNull @CallbackExecutor Executor executor, + @NonNull final CameraDevice.StateCallback callback) + throws CameraAccessException { + if (executor == null) { + throw new IllegalArgumentException("executor was null"); + } + openCameraImpl(cameraId, callback, executor, /*oomScoreOffset*/0, + getRotationOverride(mContext), /*sharedMode*/true); } + /** * Open a connection to a camera with the given ID. Also specify what oom score must be offset * by cameraserver for this client. This api can be useful for system @@ -1372,29 +1464,35 @@ public final class CameraManager { "oomScoreOffset < 0, cannot increase priority of camera client"); } openCameraImpl(cameraId, callback, executor, oomScoreOffset, - getRotationOverride(mContext)); + getRotationOverride(mContext), /*sharedMode*/false); } /** * Open a connection to a camera with the given ID, on behalf of another application. - * Also specify the minimum oom score and process state the application - * should have, as seen by the cameraserver. - * - * <p>The behavior of this method matches that of {@link #openCamera}, except that it allows - * the caller to specify the UID to use for permission/etc verification. This can only be - * done by services trusted by the camera subsystem to act on behalf of applications and - * to forward the real UID.</p> * + * @param cameraId + * The unique identifier of the camera device to open + * @param callback + * The callback which is invoked once the camera is opened + * @param executor + * The executor which will be used when invoking the callback. * @param oomScoreOffset * The minimum oom score that cameraservice must see for this client. * @param rotationOverride * The type of rotation override (none, override_to_portrait, rotation_only) * that should be followed for this camera id connection + * @param sharedMode + * Parameter specifying if the camera should be opened in shared mode. + * + * @throws CameraAccessException if the camera is disabled by device policy, + * has been disconnected, or is being used by a higher-priority camera API client in + * non shared mode. + * * @hide */ public void openCameraImpl(@NonNull String cameraId, @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor, - int oomScoreOffset, int rotationOverride) + int oomScoreOffset, int rotationOverride, boolean sharedMode) throws CameraAccessException { if (cameraId == null) { @@ -1407,24 +1505,7 @@ public final class CameraManager { } openCameraDeviceUserAsync(cameraId, callback, executor, oomScoreOffset, - rotationOverride); - } - - /** - * Open a connection to a camera with the given ID, on behalf of another application. - * - * <p>The behavior of this method matches that of {@link #openCamera}, except that it allows - * the caller to specify the UID to use for permission/etc verification. This can only be - * done by services trusted by the camera subsystem to act on behalf of applications and - * to forward the real UID.</p> - * - * @hide - */ - public void openCameraImpl(@NonNull String cameraId, - @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor) - throws CameraAccessException { - openCameraImpl(cameraId, callback, executor, /*oomScoreOffset*/0, - getRotationOverride(mContext)); + rotationOverride, sharedMode); } /** @@ -2541,6 +2622,10 @@ public final class CameraManager { } @Override public void onCameraClosed(String id, int deviceId) { + } + @Override + public void onCameraOpenedInSharedMode(String id, String clientPackageId, + int deviceId, boolean primaryClient) { }}; String[] cameraIds; @@ -3325,6 +3410,11 @@ public final class CameraManager { } @Override + public void onCameraOpenedInSharedMode(String cameraId, String clientPackageId, + int deviceId, boolean primaryClient) { + } + + @Override public void onCameraOpened(String cameraId, String clientPackageId, int deviceId) { synchronized (mLock) { onCameraOpenedLocked(new DeviceCameraInfo(cameraId, deviceId), clientPackageId); diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index 8d36fbdc8b10..d2fcfd62bfca 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -2121,6 +2121,38 @@ public abstract class CameraMetadata<TKey> { public static final int AUTOMOTIVE_LOCATION_EXTRA_RIGHT = 10; // + // Enumeration values for CameraCharacteristics#SHARED_SESSION_COLOR_SPACE + // + + /** + * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public static final int SHARED_SESSION_COLOR_SPACE_UNSPECIFIED = -1; + + /** + * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public static final int SHARED_SESSION_COLOR_SPACE_SRGB = 0; + + /** + * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public static final int SHARED_SESSION_COLOR_SPACE_DISPLAY_P3 = 7; + + /** + * @see CameraCharacteristics#SHARED_SESSION_COLOR_SPACE + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public static final int SHARED_SESSION_COLOR_SPACE_BT2020_HLG = 16; + + // // Enumeration values for CaptureRequest#COLOR_CORRECTION_MODE // diff --git a/core/java/android/hardware/camera2/CameraSharedCaptureSession.java b/core/java/android/hardware/camera2/CameraSharedCaptureSession.java new file mode 100644 index 000000000000..5426d4d10bec --- /dev/null +++ b/core/java/android/hardware/camera2/CameraSharedCaptureSession.java @@ -0,0 +1,180 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2; + +import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.view.Surface; + +import com.android.internal.camera.flags.Flags; + +import java.util.List; +import java.util.concurrent.Executor; + +/** + * A shared capture session for a {@link CameraDevice}, when a camera device is opened in shared + * mode possibly by multiple clients at the same time. + * + * <p>An active shared capture session is a special type of capture session used exclusively + * for shared camera access by multiple applications, provided the camera device supports this + * mode. To determine if a camera device supports shared mode, use the + * {@link android.hardware.camera2.CameraManager#isCameraDeviceSharingSupported} API. + * If supported, multiple clients can open the camera by calling + * {@link android.hardware.camera2.CameraManager#openSharedCamera} and create a shared capture + * session by calling {@link CameraDevice#createCaptureSession(SessionConfiguration)} and using + * session type as {@link android.hardware.camera2.params.SessionConfiguration#SESSION_SHARED}</p> + * + * <p>When an application has opened a camera device in shared mode, it can only create a shared + * capture session using session type as + * {@link android.hardware.camera2.params.SessionConfiguration#SESSION_SHARED}. Any other session + * type value will trigger {@link IllegalArgumentException}. Once the configuration is complete and + * the session is ready to actually capture data, the provided + * {@link CameraCaptureSession.StateCallback}'s + * {@link CameraCaptureSession.StateCallback#onConfigured} callback will be called and will + * receive a CameraCaptureSession (castable to {@link CameraSharedCaptureSession}).</p> + * + * <p>Shared capture sessions uses a predefined configuration detailed in + * {@link CameraCharacteristics#SHARED_SESSION_CONFIGURATION}. Using different configuration values + * when creating session will result in an {@link IllegalArgumentException}.</p> + * + * <p>When camera is opened in shared mode, the highest priority client among all the clients will + * be the primary client while the others would be secondary clients. Clients will know if they are + * primary or secondary by the device state callback + * {@link CameraDevice.StateCallback#onOpenedInSharedMode}. Once the camera has been opened in + * shared mode, their access priorities of being a primary or secondary client can change if + * another higher priority client opens the camera later. Once the camera has been opened, + * any change in primary client status will be shared by the device state callback + * {@link CameraDevice.StateCallback#onClientSharedAccessPriorityChanged}.</p> + * + * <p>The priority of client access is determined by considering two factors: its current process + * state and its "out of memory" score. Clients operating in the background are assigned a lower + * priority. In contrast, clients running in the foreground, along with system-level clients, are + * given a higher priority.</p> + * + * <p>Primary clients can create capture requests, modify any capture parameters and send them to + * the capture session for a one-shot capture or as a repeating request using the following apis: + * </p> + * + * <ul> + * + * <li>{@link CameraSharedCaptureSession#capture}</li> + * + * <li>{@link CameraSharedCaptureSession#captureSingleRequest}</li> + * + * <li>{@link CameraSharedCaptureSession#setRepeatingRequest}</li> + * + * <li>{@link CameraSharedCaptureSession#setSingleRepeatingRequest}</li> + * + * <li>{@link CameraSharedCaptureSession#stopRepeating}</li> + * + * </ul> + * + * <p>Secondary clients cannot create a capture request and modify any capture parameters. However, + * they can start the camera streaming to desired surface targets using + * {@link CameraSharedCaptureSession#startStreaming}, which will apply default parameters. Once the + * streaming has successfully started, then they can stop the streaming using + * {@link CameraSharedCaptureSession#stopStreaming}.</p> + * + * <p>The following APIs are not supported in shared capture sessions by either the primary or + * secondary client.</p> + * + * <ul> + * + * <li>{@link CameraSharedCaptureSession#captureBurst}</li> + * + * <li>{@link CameraSharedCaptureSession#captureBurstRequests}</li> + * + * <li>{@link CameraSharedCaptureSession#setRepeatingBurst}</li> + * + * <li>{@link CameraSharedCaptureSession#setRepeatingBurstRequests}</li> + * + * <li>{@link CameraSharedCaptureSession#switchToOffline}</li> + * + * <li>{@link CameraSharedCaptureSession#updateOutputConfiguration}</li> + * + * <li>{@link CameraSharedCaptureSession#finalizeOutputConfigurations}</li> + * + * <li>{@link CameraSharedCaptureSession#prepare}</li> + * + * </ul> + * + * @hide + */ +@FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) +@SystemApi +public abstract class CameraSharedCaptureSession extends CameraCaptureSession { + + /** + * Request start of the streaming of camera images by this shared capture session. + * + * <p>With this method, the camera device will continually capture images + * using the settings provided by primary client if there is ongoing repeating request + * by the primary client or default settings if no ongoing streaming request in progress.</p> + * + * <p> startStreaming has lower priority than the capture requests submitted + * through {@link #capture} by primary client, so if {@link #capture} is called when a + * streaming is active, the capture request will be processed before any further + * streaming requests are processed.</p> + * + * <p>To stop the streaming, call {@link #stopStreaming}</p> + * + * <p>Calling this method will replace any earlier streaming set up by this method.</p> + * + * @param surfaces List of target surfaces to use for streaming. + * @param executor The executor which will be used for invoking the listener. + * @param listener The callback object to notify the status and progress of the image capture. + * + * @return int A unique capture sequence ID used by + * {@link CaptureCallback#onCaptureSequenceCompleted}. + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because the session + * was explicitly closed, a new session has been created + * or the camera device has been closed. + * @throws IllegalArgumentException If the request references no surfaces or references surfaces + * that are not currently configured as outputs; or + * the executor is null, or the listener is null. + * @see #stopStreaming + * + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + @SystemApi + public abstract int startStreaming(@NonNull List<Surface> surfaces, + @NonNull @CallbackExecutor Executor executor, @NonNull CaptureCallback listener) + throws CameraAccessException; + + /** + * <p>Cancel any ongoing streaming started by {@link #startStreaming}</p> + * + * @throws CameraAccessException if the camera device is no longer connected or has + * encountered a fatal error + * @throws IllegalStateException if this session is no longer active, either because the session + * was explicitly closed, a new session has been created + * or the camera device has been closed. + * + * @see #startStreaming + * + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + @SystemApi + public abstract void stopStreaming() throws CameraAccessException; +} diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 84072585d7f0..ea70abb55b48 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -18,6 +18,7 @@ package android.hardware.camera2.impl; import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.compat.CompatChanges; @@ -41,12 +42,15 @@ import android.hardware.camera2.ICameraDeviceCallbacks; import android.hardware.camera2.ICameraDeviceUser; import android.hardware.camera2.ICameraOfflineSession; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.DynamicRangeProfiles; import android.hardware.camera2.params.ExtensionSessionConfiguration; import android.hardware.camera2.params.InputConfiguration; import android.hardware.camera2.params.MultiResolutionStreamConfigurationMap; import android.hardware.camera2.params.MultiResolutionStreamInfo; import android.hardware.camera2.params.OutputConfiguration; import android.hardware.camera2.params.SessionConfiguration; +import android.hardware.camera2.params.SharedSessionConfiguration; +import android.hardware.camera2.params.SharedSessionConfiguration.SharedOutputConfiguration; import android.hardware.camera2.params.StreamConfigurationMap; import android.hardware.camera2.utils.SubmitInfo; import android.hardware.camera2.utils.SurfaceUtils; @@ -188,6 +192,8 @@ public class CameraDeviceImpl extends CameraDevice private ExecutorService mOfflineSwitchService; private CameraOfflineSessionImpl mOfflineSessionImpl; + private boolean mSharedMode; + private boolean mIsPrimaryClient; // Runnables for all state transitions, except error, which needs the // error code argument @@ -208,6 +214,25 @@ public class CameraDeviceImpl extends CameraDevice } }; + private final Runnable mCallOnOpenedInSharedMode = new Runnable() { + @Override + public void run() { + if (!Flags.cameraMultiClient()) { + return; + } + StateCallbackKK sessionCallback = null; + synchronized (mInterfaceLock) { + if (mRemoteDevice == null) return; // Camera already closed + + sessionCallback = mSessionStateCallback; + } + if (sessionCallback != null) { + sessionCallback.onOpenedInSharedMode(CameraDeviceImpl.this, mIsPrimaryClient); + } + mDeviceCallback.onOpenedInSharedMode(CameraDeviceImpl.this, mIsPrimaryClient); + } + }; + private final Runnable mCallOnUnconfigured = new Runnable() { @Override public void run() { @@ -322,6 +347,32 @@ public class CameraDeviceImpl extends CameraDevice } }); } + + public void onOpenedInSharedMode(@NonNull CameraDevice camera, boolean primaryClient) { + if (!Flags.cameraMultiClient()) { + return; + } + mClientExecutor.execute(new Runnable() { + @Override + public void run() { + mClientStateCallback.onOpenedInSharedMode(camera, primaryClient); + } + }); + } + + public void onClientSharedAccessPriorityChanged(@NonNull CameraDevice camera, + boolean primaryClient) { + if (!Flags.cameraMultiClient()) { + return; + } + mClientExecutor.execute(new Runnable() { + @Override + public void run() { + mClientStateCallback.onClientSharedAccessPriorityChanged(camera, primaryClient); + } + }); + } + @Override public void onOpened(@NonNull CameraDevice camera) { mClientExecutor.execute(new Runnable() { @@ -358,7 +409,8 @@ public class CameraDeviceImpl extends CameraDevice @NonNull CameraManager manager, int appTargetSdkVersion, Context ctx, - @Nullable CameraDevice.CameraDeviceSetup cameraDeviceSetup) { + @Nullable CameraDevice.CameraDeviceSetup cameraDeviceSetup, + boolean sharedMode) { if (cameraId == null || callback == null || executor == null || characteristics == null || manager == null) { throw new IllegalArgumentException("Null argument given"); @@ -375,6 +427,7 @@ public class CameraDeviceImpl extends CameraDevice mAppTargetSdkVersion = appTargetSdkVersion; mContext = ctx; mCameraDeviceSetup = cameraDeviceSetup; + mSharedMode = sharedMode; final int MAX_TAG_LEN = 23; String tag = String.format("CameraDevice-JV-%s", mCameraId); @@ -438,7 +491,12 @@ public class CameraDeviceImpl extends CameraDevice } } - mDeviceExecutor.execute(mCallOnOpened); + if (Flags.cameraMultiClient() && mSharedMode) { + mIsPrimaryClient = mRemoteDevice.isPrimaryClient(); + mDeviceExecutor.execute(mCallOnOpenedInSharedMode); + } else { + mDeviceExecutor.execute(mCallOnOpened); + } mDeviceExecutor.execute(mCallOnUnconfigured); mRemoteDeviceInit = true; @@ -576,7 +634,11 @@ public class CameraDeviceImpl extends CameraDevice stopRepeating(); try { - waitUntilIdle(); + // if device is opened in shared mode, there can be multiple clients accessing the + // camera device. So do not wait for idle if the device is opened in shared mode. + if (!mSharedMode) { + waitUntilIdle(); + } mRemoteDevice.beginConfigure(); @@ -764,6 +826,54 @@ public class CameraDeviceImpl extends CameraDevice checkAndWrapHandler(handler), operatingMode, /*sessionParams*/ null); } + private boolean checkSharedOutputConfiguration(OutputConfiguration outConfig) { + if (!Flags.cameraMultiClient()) { + return false; + } + SharedSessionConfiguration sharedSessionConfiguration = + mCharacteristics.get(CameraCharacteristics.SHARED_SESSION_CONFIGURATION); + if (sharedSessionConfiguration == null) { + return false; + } + + List<SharedOutputConfiguration> sharedConfigs = + sharedSessionConfiguration.getOutputStreamsInformation(); + for (SharedOutputConfiguration sharedConfig : sharedConfigs) { + if (outConfig.getConfiguredSize().equals(sharedConfig.getSize()) + && (outConfig.getConfiguredFormat() == sharedConfig.getFormat()) + && (outConfig.getSurfaceGroupId() == OutputConfiguration.SURFACE_GROUP_ID_NONE) + && (outConfig.getSurfaceType() == sharedConfig.getSurfaceType()) + && (outConfig.getMirrorMode() == sharedConfig.getMirrorMode()) + && (outConfig.getUsage() == sharedConfig.getUsage()) + && (outConfig.isReadoutTimestampEnabled() + == sharedConfig.isReadoutTimestampEnabled()) + && (outConfig.getTimestampBase() == sharedConfig.getTimestampBase()) + && (outConfig.getStreamUseCase() == sharedConfig.getStreamUseCase()) + && (outConfig.getColorSpace().equals( + sharedSessionConfiguration.getColorSpace())) + && (outConfig.getDynamicRangeProfile() + == DynamicRangeProfiles.STANDARD) + && (outConfig.getConfiguredDataspace() == sharedConfig.getDataspace()) + && (Objects.equals(outConfig.getPhysicalCameraId(), + sharedConfig.getPhysicalCameraId())) + && (outConfig.getSensorPixelModes().isEmpty()) + && (!outConfig.isShared())) { + //Found valid config, return true + return true; + } + } + return false; + } + + private boolean checkSharedSessionConfiguration(List<OutputConfiguration> outputConfigs) { + for (OutputConfiguration out : outputConfigs) { + if (!checkSharedOutputConfiguration(out)) { + return false; + } + } + return true; + } + @Override public void createCaptureSession(SessionConfiguration config) throws CameraAccessException { @@ -778,6 +888,14 @@ public class CameraDeviceImpl extends CameraDevice if (config.getExecutor() == null) { throw new IllegalArgumentException("Invalid executor"); } + if (mSharedMode) { + if (config.getSessionType() != SessionConfiguration.SESSION_SHARED) { + throw new IllegalArgumentException("Invalid session type"); + } + if (!checkSharedSessionConfiguration(outputConfigs)) { + throw new IllegalArgumentException("Invalid output configurations"); + } + } createCaptureSessionInternal(config.getInputConfiguration(), outputConfigs, config.getStateCallback(), config.getExecutor(), config.getSessionType(), config.getSessionParameters()); @@ -801,6 +919,11 @@ public class CameraDeviceImpl extends CameraDevice throw new IllegalArgumentException("Constrained high speed session doesn't support" + " input configuration yet."); } + boolean isSharedSession = (operatingMode == ICameraDeviceUser.SHARED_MODE); + if (isSharedSession && inputConfig != null) { + throw new IllegalArgumentException("Shared capture session doesn't support" + + " input configuration yet."); + } if (mCurrentExtensionSession != null) { mCurrentExtensionSession.commitStats(); @@ -860,6 +983,10 @@ public class CameraDeviceImpl extends CameraDevice newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++, callback, executor, this, mDeviceExecutor, configureSuccess, mCharacteristics); + } else if (isSharedSession) { + newSession = new CameraSharedCaptureSessionImpl(mNextSessionId++, + callback, executor, this, mDeviceExecutor, configureSuccess, + mIsPrimaryClient); } else { newSession = new CameraCaptureSessionImpl(mNextSessionId++, input, callback, executor, this, mDeviceExecutor, configureSuccess); @@ -1882,6 +2009,40 @@ public class CameraDeviceImpl extends CameraDevice } } + /** + * Callback when client access priorities change when camera is opened in shared mode. + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public void onClientSharedAccessPriorityChanged(boolean primaryClient) { + if (DEBUG) { + Log.d(TAG, String.format( + "onClientSharedAccessPriorityChanged received, primary client = " + + primaryClient)); + } + synchronized (mInterfaceLock) { + if (mRemoteDevice == null && mRemoteDeviceInit) { + return; // Camera already closed, user is not interested in this callback anymore. + } + final long ident = Binder.clearCallingIdentity(); + try { + mDeviceExecutor.execute(obtainRunnable( + CameraDeviceImpl::notifyClientSharedAccessPriorityChanged, this, + primaryClient).recycleOnUse()); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + } + + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + private void notifyClientSharedAccessPriorityChanged(boolean primaryClient) { + if (!CameraDeviceImpl.this.isClosed()) { + mIsPrimaryClient = primaryClient; + mDeviceCallback.onClientSharedAccessPriorityChanged(CameraDeviceImpl.this, + primaryClient); + } + } + public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) { if (DEBUG) { Log.d(TAG, String.format( @@ -2447,6 +2608,12 @@ public class CameraDeviceImpl extends CameraDevice } @Override + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public void onClientSharedAccessPriorityChanged(boolean primaryClient) { + CameraDeviceImpl.this.onClientSharedAccessPriorityChanged(primaryClient); + } + + @Override public void onPrepared(int streamId) { final OutputConfiguration output; final StateCallbackKK sessionCallback; diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java index 1cc085658bfa..c0a5928a369b 100644 --- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java +++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java @@ -63,6 +63,7 @@ import android.hardware.camera2.params.OisSample; import android.hardware.camera2.params.RecommendedStreamConfiguration; import android.hardware.camera2.params.RecommendedStreamConfigurationMap; import android.hardware.camera2.params.ReprocessFormatsMap; +import android.hardware.camera2.params.SharedSessionConfiguration; import android.hardware.camera2.params.StreamConfiguration; import android.hardware.camera2.params.StreamConfigurationDuration; import android.hardware.camera2.params.StreamConfigurationMap; @@ -866,6 +867,15 @@ public class CameraMetadataNative implements Parcelable { return (T) metadata.getLensIntrinsicSamples(); } }); + sGetCommandMap.put( + CameraCharacteristics.SHARED_SESSION_CONFIGURATION.getNativeKey(), + new GetCommand() { + @Override + @SuppressWarnings("unchecked") + public <T> T getValue(CameraMetadataNative metadata, Key<T> key) { + return (T) metadata.getSharedSessionConfiguration(); + } + }); } private int[] getAvailableFormats() { @@ -1658,6 +1668,22 @@ public class CameraMetadataNative implements Parcelable { listHighResolution); } + private SharedSessionConfiguration getSharedSessionConfiguration() { + if (!Flags.cameraMultiClient()) { + return null; + } + Integer sharedSessionColorSpace = getBase( + CameraCharacteristics.SHARED_SESSION_COLOR_SPACE); + long[] sharedOutputConfigurations = getBase( + CameraCharacteristics.SHARED_SESSION_OUTPUT_CONFIGURATIONS); + + if ((sharedSessionColorSpace == null) || (sharedOutputConfigurations == null)) { + return null; + } + + return new SharedSessionConfiguration(sharedSessionColorSpace, sharedOutputConfigurations); + } + private StreamConfigurationMap getStreamConfigurationMapMaximumResolution() { StreamConfiguration[] configurations = getBase( CameraCharacteristics.SCALER_AVAILABLE_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION); diff --git a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java index eb2ff88ec1b2..1769c4638805 100644 --- a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java @@ -16,11 +16,13 @@ package android.hardware.camera2.impl; +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.FlaggedApi; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraDevice; -import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraOfflineSession; import android.hardware.camera2.CameraOfflineSession.CameraOfflineSessionCallback; import android.hardware.camera2.CaptureFailure; @@ -40,15 +42,15 @@ import android.util.Range; import android.util.SparseArray; import android.view.Surface; +import com.android.internal.camera.flags.Flags; + import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.Executor; - -import static com.android.internal.util.Preconditions.*; +import java.util.concurrent.atomic.AtomicBoolean; public class CameraOfflineSessionImpl extends CameraOfflineSession implements IBinder.DeathRecipient { @@ -176,6 +178,12 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession } @Override + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + public void onClientSharedAccessPriorityChanged(boolean primaryClient) { + Log.v(TAG, "onClientSharedAccessPriorityChanged primaryClient = " + primaryClient); + } + + @Override public void onDeviceIdle() { synchronized(mInterfaceLock) { if (mRemoteSession == null) { diff --git a/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java new file mode 100644 index 000000000000..a1f31c0ced5e --- /dev/null +++ b/core/java/android/hardware/camera2/impl/CameraSharedCaptureSessionImpl.java @@ -0,0 +1,242 @@ +/* + * 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 android.hardware.camera2.impl; + +import android.annotation.FlaggedApi; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraSharedCaptureSession; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.params.OutputConfiguration; +import android.os.ConditionVariable; +import android.os.Handler; +import android.view.Surface; + +import com.android.internal.camera.flags.Flags; + +import java.util.List; +import java.util.concurrent.Executor; + +/** + * Standard implementation of CameraSharedCaptureSession. + * + * <p> + * Mostly just forwards calls to an instance of CameraCaptureSessionImpl, + * but implements the few necessary behavior changes and additional methods required + * for the shared session mode. + * </p> + */ +@FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) +public class CameraSharedCaptureSessionImpl + extends CameraSharedCaptureSession implements CameraCaptureSessionCore { + private static final String TAG = "CameraSharedCaptureSessionImpl"; + private final CameraCaptureSessionImpl mSessionImpl; + private final ConditionVariable mInitialized = new ConditionVariable(); + private boolean mIsPrimary; + + /** + * Create a new CameraCaptureSession. + */ + CameraSharedCaptureSessionImpl(int id, + CameraCaptureSession.StateCallback callback, Executor stateExecutor, + android.hardware.camera2.impl.CameraDeviceImpl deviceImpl, + Executor deviceStateExecutor, boolean configureSuccess, boolean isPrimary) { + CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback); + mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback, + stateExecutor, deviceImpl, deviceStateExecutor, configureSuccess); + mIsPrimary = isPrimary; + mInitialized.open(); + } + + @Override + public int startStreaming(List<Surface> surfaces, Executor executor, CaptureCallback listener) + throws CameraAccessException { + // Todo: Need to add implementation. + return 0; + } + + @Override + public void stopStreaming() throws CameraAccessException { + // Todo: Need to add implementation. + } + + @Override + public void close() { + mSessionImpl.close(); + } + + @Override + public Surface getInputSurface() { + return null; + } + + @Override + public boolean isReprocessable() { + return false; + } + + @Override + public void abortCaptures() throws CameraAccessException { + if (mIsPrimary) { + mSessionImpl.abortCaptures(); + } + } + + @Override + public int setRepeatingRequest(CaptureRequest request, CaptureCallback listener, + Handler handler) throws CameraAccessException { + if (mIsPrimary) { + return mSessionImpl.setRepeatingRequest(request, listener, handler); + } + throw new UnsupportedOperationException("Shared capture session only supports this method" + + " for primary clients"); + } + + @Override + public void stopRepeating() throws CameraAccessException { + if (mIsPrimary) { + mSessionImpl.stopRepeating(); + } + } + + @Override + public int capture(CaptureRequest request, CaptureCallback listener, Handler handler) + throws CameraAccessException { + if (mIsPrimary) { + return mSessionImpl.capture(request, listener, handler); + } + throw new UnsupportedOperationException("Shared capture session only supports this method" + + " for primary clients"); + } + + @Override + public void tearDown(Surface surface) throws CameraAccessException { + mSessionImpl.tearDown(surface); + } + + @Override + public CameraDevice getDevice() { + return mSessionImpl.getDevice(); + } + + @Override + public boolean isAborting() { + return mSessionImpl.isAborting(); + } + + @Override + public CameraDeviceImpl.StateCallbackKK getDeviceStateCallback() { + return mSessionImpl.getDeviceStateCallback(); + } + + @Override + public void replaceSessionClose() { + mSessionImpl.replaceSessionClose(); + } + + @Override + public int setRepeatingBurst(List<CaptureRequest> requests, CaptureCallback listener, + Handler handler) throws CameraAccessException { + throw new UnsupportedOperationException("Shared Capture session doesn't support" + + " this method"); + } + + @Override + public int captureBurst(List<CaptureRequest> requests, CaptureCallback listener, + Handler handler) throws CameraAccessException { + throw new UnsupportedOperationException("Shared Capture session doesn't support" + + " this method"); + } + + @Override + public void updateOutputConfiguration(OutputConfiguration config) + throws CameraAccessException { + throw new UnsupportedOperationException("Shared capture session doesn't support" + + " this method"); + } + + @Override + public void finalizeOutputConfigurations(List<OutputConfiguration> deferredOutputConfigs) + throws CameraAccessException { + throw new UnsupportedOperationException("Shared capture session doesn't support" + + " this method"); + } + + @Override + public void prepare(Surface surface) throws CameraAccessException { + throw new UnsupportedOperationException("Shared capture session doesn't support" + + " this method"); + } + + @Override + public void prepare(int maxCount, Surface surface) throws CameraAccessException { + throw new UnsupportedOperationException("Shared capture session doesn't support" + + " this method"); + } + + @Override + public void closeWithoutDraining() { + throw new UnsupportedOperationException("Shared capture session doesn't support" + + " this method"); + } + + private class WrapperCallback extends StateCallback { + private final StateCallback mCallback; + + WrapperCallback(StateCallback callback) { + mCallback = callback; + } + + @Override + public void onConfigured(CameraCaptureSession session) { + mInitialized.block(); + mCallback.onConfigured(CameraSharedCaptureSessionImpl.this); + } + + @Override + public void onConfigureFailed(CameraCaptureSession session) { + mInitialized.block(); + mCallback.onConfigureFailed(CameraSharedCaptureSessionImpl.this); + } + + @Override + public void onReady(CameraCaptureSession session) { + mCallback.onReady(CameraSharedCaptureSessionImpl.this); + } + + @Override + public void onActive(CameraCaptureSession session) { + mCallback.onActive(CameraSharedCaptureSessionImpl.this); + } + + @Override + public void onCaptureQueueEmpty(CameraCaptureSession session) { + mCallback.onCaptureQueueEmpty(CameraSharedCaptureSessionImpl.this); + } + + @Override + public void onClosed(CameraCaptureSession session) { + mCallback.onClosed(CameraSharedCaptureSessionImpl.this); + } + + @Override + public void onSurfacePrepared(CameraCaptureSession session, Surface surface) { + mCallback.onSurfacePrepared(CameraSharedCaptureSessionImpl.this, + surface); + } + } +} diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java index aec2cff61d99..831c75ec5d33 100644 --- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java +++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java @@ -301,4 +301,16 @@ public class ICameraDeviceUserWrapper { } } + /** + * API to check if the client is primary client when camera device is opened in shared mode. + */ + public boolean isPrimaryClient() throws CameraAccessException { + try { + return mRemoteDevice.isPrimaryClient(); + } catch (ServiceSpecificException e) { + throw ExceptionUtils.throwAsPublicException(e); + } catch (RemoteException e) { + throw ExceptionUtils.throwAsPublicException(e); + } + } } diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java index d38be9b7b694..e12c46322d8c 100644 --- a/core/java/android/hardware/camera2/params/OutputConfiguration.java +++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java @@ -29,6 +29,7 @@ import android.annotation.TestApi; import android.graphics.ColorSpace; import android.graphics.ImageFormat; import android.graphics.ImageFormat.Format; +import android.hardware.DataSpace.NamedDataSpace; import android.hardware.HardwareBuffer; import android.hardware.HardwareBuffer.Usage; import android.hardware.camera2.CameraCaptureSession; @@ -1729,6 +1730,79 @@ public final class OutputConfiguration implements Parcelable { } /** + * Get the configured format associated with this {@link OutputConfiguration}. + * + * @return {@link android.graphics.ImageFormat#Format} associated with this + * {@link OutputConfiguration}. + * + * @hide + */ + public @Format int getConfiguredFormat() { + return mConfiguredFormat; + } + + /** + * Get the usage flag associated with this {@link OutputConfiguration}. + * + * @return {@link HardwareBuffer#Usage} associated with this {@link OutputConfiguration}. + * + * @hide + */ + public @Usage long getUsage() { + return mUsage; + } + + /** + * Get the surface type associated with this {@link OutputConfiguration}. + * + * @return The surface type associated with this {@link OutputConfiguration}. + * + * @see #SURFACE_TYPE_SURFACE_VIEW + * @see #SURFACE_TYPE_SURFACE_TEXTURE + * @see #SURFACE_TYPE_MEDIA_RECORDER + * @see #SURFACE_TYPE_MEDIA_CODEC + * @see #SURFACE_TYPE_IMAGE_READER + * @see #SURFACE_TYPE_UNKNOWN + * @hide + */ + public int getSurfaceType() { + return mSurfaceType; + } + + /** + * Get the sensor pixel modes associated with this {@link OutputConfiguration}. + * + * @return List of {@link #SensorPixelMode} associated with this {@link OutputConfiguration}. + * + * @hide + */ + public @NonNull List<Integer> getSensorPixelModes() { + return mSensorPixelModesUsed; + } + + /** + * Get the sharing mode associated with this {@link OutputConfiguration}. + * + * @return true if surface sharing is enabled with this {@link OutputConfiguration}. + * + * @hide + */ + public boolean isShared() { + return mIsShared; + } + + /** + * Get the dataspace associated with this {@link OutputConfiguration}. + * + * @return {@link Dataspace#NamedDataSpace} for this {@link OutputConfiguration}. + * + * @hide + */ + public @NamedDataSpace int getConfiguredDataspace() { + return mConfiguredDataspace; + } + + /** * Get the physical camera ID associated with this {@link OutputConfiguration}. * * <p>If this OutputConfiguration isn't targeting a physical camera of a logical diff --git a/core/java/android/hardware/camera2/params/SessionConfiguration.java b/core/java/android/hardware/camera2/params/SessionConfiguration.java index 50c6b5b8b995..82aa64b1474c 100644 --- a/core/java/android/hardware/camera2/params/SessionConfiguration.java +++ b/core/java/android/hardware/camera2/params/SessionConfiguration.java @@ -23,6 +23,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.graphics.ColorSpace; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; @@ -78,6 +79,19 @@ public final class SessionConfiguration implements Parcelable { CameraDevice.SESSION_OPERATION_MODE_CONSTRAINED_HIGH_SPEED; /** + * A shared session type containing instances of {@link OutputConfiguration} from a set of + * predefined stream configurations. A shared session can be shared among multiple clients. + * Shared session does not have any {@link InputConfiguration} as it does not support + * reprocessable sessions. + * + * @see CameraDevice#createCaptureSession(SessionConfiguration) + * @hide + */ + @FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) + @SystemApi + public static final int SESSION_SHARED = CameraDevice.SESSION_OPERATION_MODE_SHARED; + + /** * First vendor-specific session mode * @hide */ diff --git a/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java b/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java new file mode 100644 index 000000000000..cdcc92ce4404 --- /dev/null +++ b/core/java/android/hardware/camera2/params/SharedSessionConfiguration.java @@ -0,0 +1,312 @@ +/* + * 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 android.hardware.camera2.params; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.graphics.ColorSpace; +import android.graphics.ImageFormat.Format; +import android.hardware.DataSpace.NamedDataSpace; +import android.hardware.HardwareBuffer.Usage; +import android.hardware.camera2.params.OutputConfiguration.MirrorMode; +import android.hardware.camera2.params.OutputConfiguration.StreamUseCase; +import android.hardware.camera2.params.OutputConfiguration.TimestampBase; +import android.util.Log; +import android.util.Size; + +import com.android.internal.camera.flags.Flags; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Immutable class to store the shared session configuration + * {@link CameraCharacteristics#SHARED_SESSION_CONFIGURATION} to set up + * {@link android.view.Surface Surfaces} for creating a + * {@link android.hardware.camera2.CameraSharedCaptureSession capture session} using + * {@link android.hardware.camera2.CameraDevice#createCaptureSession(SessionConfiguration)} and + * {@link android.hardware.camera2.params.SessionConfiguration#SESSION_SHARED + * shared capture session} when camera has been opened in shared mode using + * {@link #openSharedCamera(String, Executor, StateCallback)}. + * + * <p>This is the authoritative list for all output configurations that are supported by a camera + * device when opened in shared mode.</p> + * + * <p>An instance of this object is available from {@link CameraCharacteristics} using + * the {@link CameraCharacteristics#SHARED_SESSION_CONFIGURATION} key and the + * {@link CameraCharacteristics#get} method.</p> + * + * <pre><code>{@code + * CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); + * StreamConfigurationMap configs = characteristics.get( + * CameraCharacteristics.SHARED_SESSION_CONFIGURATION); + * }</code></pre> + * + * @see CameraCharacteristics#SHARED_SESSION_CONFIGURATION + * @see CameraDevice#createCaptureSession(SessionConfiguration) + * @see SessionConfiguration#SESSION_SHARED + * @see CameraManager#openSharedCamera(String, Executor, StateCallback) + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_CAMERA_MULTI_CLIENT) +public final class SharedSessionConfiguration { + private static final String TAG = "SharedSessionConfiguration"; + // Metadata android.info.availableSharedOutputConfigurations has list of shared output + // configurations. Each output configuration has minimum of 11 entries of size long + // followed by the physical camera id if present. + // See android.info.availableSharedOutputConfigurations for details. + private static final int SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES = 11; + /** + * Immutable class to store shared output stream information. + */ + public static final class SharedOutputConfiguration { + private final int mSurfaceType; + private final Size mSize; + private final int mFormat; + private final int mDataspace; + private final long mStreamUseCase; + private String mPhysicalCameraId; + private final long mUsage; + private int mTimestampBase; + private int mMirrorMode; + private boolean mReadoutTimestampEnabled; + + /** + * Create a new {@link SharedOutputConfiguration}. + * + * @param surfaceType Surface Type for this output configuration. + * @param sz Size for this output configuration. + * @param format {@link android.graphics.ImageFormat#Format} associated with this + * {@link OutputConfiguration}. + * @param mirrorMode {@link OutputConfiguration#MirrorMode} for this output configuration. + * @param readoutTimeStampEnabled Flag indicating whether readout timestamp is enabled + * for this output configuration. + * @param timestampBase {@link OutputConfiguration#TimestampBase} for this output + * configuration. + * @param dataspace {@link Dataspace#NamedDataSpace} for this output configuration. + * @param usage {@link HardwareBuffer#Usage} for this output configuration. + * @param streamUseCase {@link OutputConfiguration#StreamUseCase} for this output + * configuration. + * @param physicalCamId Physical Camera Id for this output configuration. + * + * @hide + */ + public SharedOutputConfiguration(int surfaceType, @NonNull Size sz, @Format int format, + @MirrorMode int mirrorMode, boolean readoutTimeStampEnabled, + @TimestampBase int timestampBase, @NamedDataSpace int dataspace, @Usage long usage, + @StreamUseCase long streamUseCase, @Nullable String physicalCamId) { + mSurfaceType = surfaceType; + mSize = sz; + mFormat = format; + mMirrorMode = mirrorMode; + mReadoutTimestampEnabled = readoutTimeStampEnabled; + mTimestampBase = timestampBase; + mDataspace = dataspace; + mUsage = usage; + mStreamUseCase = streamUseCase; + mPhysicalCameraId = physicalCamId; + } + + /** + * Returns the surface type configured for the shared output configuration. + * @return SURFACE_TYPE_UNKNOWN = -1 + * SURFACE_TYPE_SURFACE_VIEW = 0 + * SURFACE_TYPE_SURFACE_TEXTURE = 1 + * SURFACE_TYPE_MEDIA_RECORDER = 2 + * SURFACE_TYPE_MEDIA_CODEC = 3 + * SURFACE_TYPE_IMAGE_READER = 4 + */ + public int getSurfaceType() { + return mSurfaceType; + } + + /** + * Returns the format of the shared output configuration. + * @return format The format of the configured output. This must be one of the + * {@link android.graphics.ImageFormat} or {@link android.graphics.PixelFormat} + * constants. Note that not all formats are supported by the camera device. + */ + public @Format int getFormat() { + return mFormat; + } + + /** + * Returns the configured size for the shared output configuration. + * @return surfaceSize Size for the shared output configuration + * + */ + public @NonNull Size getSize() { + return mSize; + } + + /** + * Return datatspace configured for the shared output configuration. + * + * @return {@link Dataspace#NamedDataSpace} configured for shared session + */ + public @NamedDataSpace int getDataspace() { + return mDataspace; + } + + /** + * Get the mirroring mode configured for the shared output configuration. + * + * @return {@link OutputConfiguration#MirrorMode} configured for the shared session + */ + public @MirrorMode int getMirrorMode() { + return mMirrorMode; + } + + /** + * Get the stream use case configured for the shared output configuration. + * + * @return {@link OutputConfiguration#StreamUseCase} configured for the shared session + */ + public @StreamUseCase long getStreamUseCase() { + return mStreamUseCase; + } + + /** + * Get the timestamp base configured for the shared output configuration. + * + * @return {@link OutputConfiguration#TimestampBase} configured for the shared session + */ + public @TimestampBase int getTimestampBase() { + return mTimestampBase; + } + + /** Whether readout timestamp is used for this shared output configuration. + * + */ + public boolean isReadoutTimestampEnabled() { + return mReadoutTimestampEnabled; + } + + /** Returns the usage if set for this shared output configuration. + * + * @return {@link HardwareBuffer#Usage} flags if set for shared output configuration with + * the ImageReader output surface. + */ + public @Usage long getUsage() { + return mUsage; + } + + public @Nullable String getPhysicalCameraId() { + return mPhysicalCameraId; + } + } + + /** + * Create a new {@link SharedSessionConfiguration}. + * + * <p>The array parameters ownership is passed to this object after creation; do not + * write to them after this constructor is invoked.</p> + * + * @param sharedColorSpace the colorspace to be used for the shared output configurations. + * @param sharedOutputConfigurations a non-{@code null} array of metadata + * android.info.availableSharedOutputConfigurations + * + * @hide + */ + public SharedSessionConfiguration(int sharedColorSpace, + @NonNull long[] sharedOutputConfigurations) { + mColorSpace = sharedColorSpace; + byte physicalCameraIdLen; + int surfaceType, width, height, format, mirrorMode, timestampBase, dataspace; + long usage, streamUseCase; + boolean isReadOutTimestampEnabled; + // Parse metadata android.info.availableSharedOutputConfigurations which contains + // list of shared output configurations. + int numOfEntries = sharedOutputConfigurations.length; + int i = 0; + while (numOfEntries >= SharedSessionConfiguration.SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES) { + surfaceType = (int) sharedOutputConfigurations[i]; + width = (int) sharedOutputConfigurations[i + 1]; + height = (int) sharedOutputConfigurations[i + 2]; + format = (int) sharedOutputConfigurations[i + 3]; + mirrorMode = (int) sharedOutputConfigurations[i + 4]; + isReadOutTimestampEnabled = (sharedOutputConfigurations[i + 5] != 0); + timestampBase = (int) sharedOutputConfigurations[i + 6]; + dataspace = (int) sharedOutputConfigurations[i + 7]; + usage = sharedOutputConfigurations[i + 8]; + streamUseCase = sharedOutputConfigurations[i + 9]; + physicalCameraIdLen = (byte) sharedOutputConfigurations[i + 10]; + numOfEntries -= SharedSessionConfiguration.SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES; + i += SharedSessionConfiguration.SHARED_OUTPUT_CONFIG_NUM_OF_ENTRIES; + if (numOfEntries < physicalCameraIdLen) { + Log.e(TAG, "Number of remaining data in shared configuration is less than" + + " physical camera id length . Malformed metadata" + + " android.info.availableSharedOutputConfigurations."); + break; + } + StringBuilder physicalCameraId = new StringBuilder(); + long asciiValue; + for (int j = 0; j < physicalCameraIdLen; j++) { + asciiValue = sharedOutputConfigurations[i + j]; + if (asciiValue == 0) { // Check for null terminator + break; + } + physicalCameraId.append((char) asciiValue); + } + SharedOutputConfiguration outputInfo; + outputInfo = new SharedOutputConfiguration(surfaceType, new Size(width, height), + format, mirrorMode, isReadOutTimestampEnabled, timestampBase, + dataspace, usage, streamUseCase, physicalCameraId.toString()); + mOutputStreamConfigurations.add(outputInfo); + i += physicalCameraIdLen; + numOfEntries -= physicalCameraIdLen; + } + if (numOfEntries != 0) { + Log.e(TAG, "Unexpected entries left in shared output configuration." + + " Malformed metadata android.info.availableSharedOutputConfigurations."); + } + } + + /** + * Return the shared session color space which is configured. + * + * @return the shared session color space + */ + @SuppressLint("MethodNameUnits") + public @Nullable ColorSpace getColorSpace() { + if (mColorSpace != ColorSpaceProfiles.UNSPECIFIED) { + return ColorSpace.get(ColorSpace.Named.values()[mColorSpace]); + } else { + return null; + } + } + /** + * Get information about each shared output configuarion in the shared session. + * + * @return Non-modifiable list of output configuration. + * + */ + public @NonNull List<SharedOutputConfiguration> getOutputStreamsInformation() { + return Collections.unmodifiableList(mOutputStreamConfigurations); + } + + private int mColorSpace; + private final ArrayList<SharedOutputConfiguration> mOutputStreamConfigurations = + new ArrayList<SharedOutputConfiguration>(); +} + diff --git a/core/java/android/hardware/contexthub/HubDiscoveryInfo.java b/core/java/android/hardware/contexthub/HubDiscoveryInfo.java new file mode 100644 index 000000000000..581040dbfa56 --- /dev/null +++ b/core/java/android/hardware/contexthub/HubDiscoveryInfo.java @@ -0,0 +1,73 @@ +/* + * 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 android.hardware.contexthub; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.chre.flags.Flags; +import android.hardware.location.ContextHubManager; + +/** + * Class that represents the result of from an hub endpoint discovery. + * + * <p>The type is returned from an endpoint discovery query via {@link + * ContextHubManager#findEndpoints}. + * + * <p>Application may use the values {@link #getHubEndpointInfo} to retrieve the {@link + * HubEndpointInfo} that describes the endpoint that matches the query. + * + * <p>Application may use the values {@link #getHubServiceInfo()} to retrieve the {@link + * HubServiceInfo} that describes the service that matches the query. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public class HubDiscoveryInfo { + @NonNull private final HubEndpointInfo mEndpointInfo; + @Nullable private final HubServiceInfo mServiceInfo; + + /** @hide */ + public HubDiscoveryInfo(@NonNull HubEndpointInfo endpointInfo) { + mEndpointInfo = endpointInfo; + mServiceInfo = null; + } + + /** @hide */ + public HubDiscoveryInfo( + @NonNull HubEndpointInfo endpointInfo, @NonNull HubServiceInfo serviceInfo) { + mEndpointInfo = endpointInfo; + mServiceInfo = serviceInfo; + } + + /** Get the {@link HubEndpointInfo} for the endpoint found. */ + @NonNull + public HubEndpointInfo getHubEndpointInfo() { + return mEndpointInfo; + } + + /** + * Get the {@link HubServiceInfo} for the endpoint found. The value will be null if there is no + * service info specified in the query. + */ + @Nullable + public HubServiceInfo getHubServiceInfo() { + return mServiceInfo; + } +} diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java new file mode 100644 index 000000000000..078b4d4629e0 --- /dev/null +++ b/core/java/android/hardware/contexthub/HubEndpoint.java @@ -0,0 +1,559 @@ +/* + * 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 android.hardware.contexthub; + +import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.chre.flags.Flags; +import android.content.Context; +import android.hardware.location.IContextHubService; +import android.hardware.location.IContextHubTransactionCallback; +import android.os.RemoteException; +import android.util.Log; +import android.util.SparseArray; + +import androidx.annotation.GuardedBy; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * An object representing an endpoint exposed to ContextHub and VendorHub. The object encapsulates + * the lifecycle and message callbacks for an endpoint. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public class HubEndpoint { + private static final String TAG = "HubEndpoint"; + + private final Object mLock = new Object(); + private final HubEndpointInfo mPendingHubEndpointInfo; + @Nullable private final IHubEndpointLifecycleCallback mLifecycleCallback; + @Nullable private final IHubEndpointMessageCallback mMessageCallback; + @NonNull private final Executor mLifecycleCallbackExecutor; + @NonNull private final Executor mMessageCallbackExecutor; + + @GuardedBy("mLock") + private final SparseArray<HubEndpointSession> mActiveSessions = new SparseArray<>(); + + private final IContextHubEndpointCallback mServiceCallback = + new IContextHubEndpointCallback.Stub() { + @Override + public void onSessionOpenRequest( + int sessionId, + HubEndpointInfo initiator, + @Nullable HubServiceInfo serviceInfo) + throws RemoteException { + HubEndpointSession activeSession; + synchronized (mLock) { + activeSession = mActiveSessions.get(sessionId); + // TODO(b/378974199): Consider refactor these assertions + if (activeSession != null) { + Log.i( + TAG, + "onSessionOpenComplete: session already exists, id=" + + sessionId); + return; + } + } + + if (mLifecycleCallback != null) { + mLifecycleCallbackExecutor.execute( + () -> + processSessionOpenRequestResult( + sessionId, + initiator, + serviceInfo, + mLifecycleCallback.onSessionOpenRequest( + initiator, serviceInfo))); + } + } + + private void processSessionOpenRequestResult( + int sessionId, + HubEndpointInfo initiator, + @Nullable HubServiceInfo serviceInfo, + HubEndpointSessionResult result) { + if (result == null) { + throw new IllegalArgumentException( + "HubEndpointSessionResult shouldn't be null."); + } + + if (result.isAccepted()) { + acceptSession(sessionId, initiator, serviceInfo); + } else { + Log.i( + TAG, + "Session " + + sessionId + + " from " + + initiator + + " was rejected, reason=" + + result.getReason()); + rejectSession(sessionId); + } + } + + private void acceptSession( + int sessionId, + HubEndpointInfo initiator, + @Nullable HubServiceInfo serviceInfo) { + if (mServiceToken == null || mAssignedHubEndpointInfo == null) { + // No longer registered? + return; + } + + // Retrieve the active session + HubEndpointSession activeSession; + synchronized (mLock) { + activeSession = mActiveSessions.get(sessionId); + // TODO(b/378974199): Consider refactor these assertions + if (activeSession != null) { + Log.e( + TAG, + "onSessionOpenRequestResult: session already exists, id=" + + sessionId); + return; + } + + activeSession = + new HubEndpointSession( + sessionId, + HubEndpoint.this, + mAssignedHubEndpointInfo, + initiator, + serviceInfo); + try { + // oneway call to notify system service that the request is completed + mServiceToken.openSessionRequestComplete(sessionId); + } catch (RemoteException e) { + Log.e(TAG, "onSessionOpenRequestResult: ", e); + return; + } + + mActiveSessions.put(sessionId, activeSession); + } + + // Execute the callback + activeSession.setOpened(); + if (mLifecycleCallback != null) { + final HubEndpointSession finalActiveSession = activeSession; + mLifecycleCallbackExecutor.execute( + () -> mLifecycleCallback.onSessionOpened(finalActiveSession)); + } + } + + private void rejectSession(int sessionId) { + if (mServiceToken == null || mAssignedHubEndpointInfo == null) { + // No longer registered? + return; + } + + try { + mServiceToken.closeSession( + sessionId, + IHubEndpointLifecycleCallback + .REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + + @Override + public void onSessionOpenComplete(int sessionId) throws RemoteException { + final HubEndpointSession activeSession; + + // Retrieve the active session + synchronized (mLock) { + activeSession = mActiveSessions.get(sessionId); + } + // TODO(b/378974199): Consider refactor these assertions + if (activeSession == null) { + Log.i( + TAG, + "onSessionOpenComplete: no pending session open request? id=" + + sessionId); + return; + } + + // Execute the callback + activeSession.setOpened(); + if (mLifecycleCallback != null) { + mLifecycleCallbackExecutor.execute( + () -> mLifecycleCallback.onSessionOpened(activeSession)); + } + } + + @Override + public void onSessionClosed(int sessionId, int reason) throws RemoteException { + final HubEndpointSession activeSession; + + // Retrieve the active session + synchronized (mLock) { + activeSession = mActiveSessions.get(sessionId); + } + // TODO(b/378974199): Consider refactor these assertions + if (activeSession == null) { + Log.i(TAG, "onSessionClosed: session not active, id=" + sessionId); + return; + } + + // Execute the callback + if (mLifecycleCallback != null) { + mLifecycleCallbackExecutor.execute( + () -> { + mLifecycleCallback.onSessionClosed(activeSession, reason); + + // Remove the session object first to call + activeSession.setClosed(); + synchronized (mLock) { + mActiveSessions.remove(sessionId); + } + }); + } + } + + @Override + public void onMessageReceived(int sessionId, HubMessage message) + throws RemoteException { + final HubEndpointSession activeSession; + + // Retrieve the active session + synchronized (mLock) { + activeSession = mActiveSessions.get(sessionId); + } + if (activeSession == null) { + Log.i(TAG, "onMessageReceived: session not active, id=" + sessionId); + } + + if (activeSession == null || mMessageCallback == null) { + if (message.getDeliveryParams().isResponseRequired()) { + try { + mServiceToken.sendMessageDeliveryStatus( + sessionId, + message.getMessageSequenceNumber(), + ErrorCode.DESTINATION_NOT_FOUND); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + return; + } + + // Execute the callback + mMessageCallbackExecutor.execute( + () -> { + mMessageCallback.onMessageReceived(activeSession, message); + if (message.getDeliveryParams().isResponseRequired()) { + try { + mServiceToken.sendMessageDeliveryStatus( + sessionId, + message.getMessageSequenceNumber(), + ErrorCode.OK); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + }); + } + }; + + /** Binder returned from system service, non-null while registered. */ + @Nullable private IContextHubEndpoint mServiceToken; + + /** HubEndpointInfo with the assigned endpoint id from system service. */ + @Nullable private HubEndpointInfo mAssignedHubEndpointInfo; + + private HubEndpoint( + @NonNull HubEndpointInfo pendingEndpointInfo, + @Nullable IHubEndpointLifecycleCallback endpointLifecycleCallback, + @NonNull Executor lifecycleCallbackExecutor, + @Nullable IHubEndpointMessageCallback endpointMessageCallback, + @NonNull Executor messageCallbackExecutor) { + mPendingHubEndpointInfo = pendingEndpointInfo; + + mLifecycleCallback = endpointLifecycleCallback; + mLifecycleCallbackExecutor = lifecycleCallbackExecutor; + mMessageCallback = endpointMessageCallback; + mMessageCallbackExecutor = messageCallbackExecutor; + } + + /** @hide */ + public void register(IContextHubService service) { + // TODO(b/378974199): Consider refactor these assertions + if (mServiceToken != null) { + // Already registered + return; + } + try { + IContextHubEndpoint serviceToken = + service.registerEndpoint(mPendingHubEndpointInfo, mServiceCallback); + mAssignedHubEndpointInfo = serviceToken.getAssignedHubEndpointInfo(); + mServiceToken = serviceToken; + } catch (RemoteException e) { + Log.e(TAG, "registerEndpoint: failed to register endpoint", e); + e.rethrowFromSystemServer(); + } + } + + /** @hide */ + public void unregister() { + IContextHubEndpoint serviceToken = mServiceToken; + // TODO(b/378974199): Consider refactor these assertions + if (serviceToken == null) { + // Not yet registered + return; + } + + try { + synchronized (mLock) { + // Don't call HubEndpointSession.close() here. + for (int i = 0; i < mActiveSessions.size(); i++) { + mActiveSessions.get(mActiveSessions.keyAt(i)).setClosed(); + } + mActiveSessions.clear(); + } + mServiceToken.unregister(); + } catch (RemoteException e) { + Log.e(TAG, "unregisterEndpoint: failed to unregister endpoint", e); + e.rethrowFromSystemServer(); + } finally { + mServiceToken = null; + mAssignedHubEndpointInfo = null; + } + } + + /** @hide */ + public void openSession(HubEndpointInfo destinationInfo, @Nullable HubServiceInfo serviceInfo) { + // TODO(b/378974199): Consider refactor these assertions + if (mServiceToken == null || mAssignedHubEndpointInfo == null) { + // No longer registered? + return; + } + + HubEndpointSession newSession; + try { + // Request system service to assign session id. + int sessionId = mServiceToken.openSession(destinationInfo, serviceInfo); + + // Save the newly created session + synchronized (mLock) { + newSession = + new HubEndpointSession( + sessionId, + HubEndpoint.this, + destinationInfo, + mAssignedHubEndpointInfo, + serviceInfo); + mActiveSessions.put(sessionId, newSession); + } + } catch (RemoteException e) { + // Move this to toString + Log.e(TAG, "openSession: failed to open session to " + destinationInfo, e); + e.rethrowFromSystemServer(); + } + } + + /** @hide */ + public void closeSession(HubEndpointSession session) { + IContextHubEndpoint serviceToken = mServiceToken; + // TODO(b/378974199): Consider refactor these assertions + if (serviceToken == null || mAssignedHubEndpointInfo == null) { + // Not registered + return; + } + + synchronized (mLock) { + if (!mActiveSessions.contains(session.getId())) { + // Already closed? + return; + } + session.setClosed(); + mActiveSessions.remove(session.getId()); + } + + try { + // Oneway notification to system service + serviceToken.closeSession( + session.getId(), + IHubEndpointLifecycleCallback.REASON_CLOSE_ENDPOINT_SESSION_REQUESTED); + } catch (RemoteException e) { + Log.e(TAG, "closeSession: failed to close session " + session, e); + e.rethrowFromSystemServer(); + } + } + + void sendMessage( + HubEndpointSession session, + HubMessage message, + @Nullable IContextHubTransactionCallback transactionCallback) { + IContextHubEndpoint serviceToken = mServiceToken; + if (serviceToken == null) { + // Not registered + return; + } + + try { + serviceToken.sendMessage(session.getId(), message, transactionCallback); + } catch (RemoteException e) { + Log.e(TAG, "sendMessage: failed to send message session=" + session, e); + e.rethrowFromSystemServer(); + } + } + + public int getVersion() { + return mPendingHubEndpointInfo.getVersion(); + } + + @Nullable + public String getTag() { + return mPendingHubEndpointInfo.getTag(); + } + + @NonNull + public Collection<HubServiceInfo> getServiceInfoCollection() { + return mPendingHubEndpointInfo.getServiceInfoCollection(); + } + + @Nullable + public IHubEndpointLifecycleCallback getLifecycleCallback() { + return mLifecycleCallback; + } + + @Nullable + public IHubEndpointMessageCallback getMessageCallback() { + return mMessageCallback; + } + + /** Builder for a {@link HubEndpoint} object. */ + public static final class Builder { + private final String mPackageName; + + @Nullable private IHubEndpointLifecycleCallback mLifecycleCallback; + + @NonNull private Executor mLifecycleCallbackExecutor; + + @Nullable private IHubEndpointMessageCallback mMessageCallback; + @NonNull private Executor mMessageCallbackExecutor; + + private int mVersion; + @Nullable private String mTag; + + private List<HubServiceInfo> mServiceInfos = Collections.emptyList(); + + /** Create a builder for {@link HubEndpoint} */ + public Builder(@NonNull Context context) { + mPackageName = context.getPackageName(); + mVersion = (int) context.getApplicationInfo().longVersionCode; + mLifecycleCallbackExecutor = context.getMainExecutor(); + mMessageCallbackExecutor = context.getMainExecutor(); + } + + /** + * Set the version for the endpoint. Default is 0. + * + * @hide + */ + @NonNull + public Builder setVersion(int version) { + mVersion = version; + return this; + } + + /** + * Set a tag string. The tag can be used to further identify the creator of the endpoint. + * Endpoints created by the same package share the same name but should have different tags. + */ + @NonNull + public Builder setTag(@NonNull String tag) { + mTag = tag; + return this; + } + + /** Attach a callback interface for lifecycle events for this Endpoint */ + @NonNull + public Builder setLifecycleCallback( + @NonNull IHubEndpointLifecycleCallback lifecycleCallback) { + mLifecycleCallback = lifecycleCallback; + return this; + } + + /** + * Attach a callback interface for lifecycle events for this Endpoint with a specified + * executor + */ + @NonNull + public Builder setLifecycleCallback( + @NonNull @CallbackExecutor Executor executor, + @NonNull IHubEndpointLifecycleCallback lifecycleCallback) { + mLifecycleCallbackExecutor = executor; + mLifecycleCallback = lifecycleCallback; + return this; + } + + /** Attach a callback interface for message events for this Endpoint */ + @NonNull + public Builder setMessageCallback(@NonNull IHubEndpointMessageCallback messageCallback) { + mMessageCallback = messageCallback; + return this; + } + + /** + * Attach a callback interface for message events for this Endpoint with a specified + * executor + */ + @NonNull + public Builder setMessageCallback( + @NonNull @CallbackExecutor Executor executor, + @NonNull IHubEndpointMessageCallback messageCallback) { + mMessageCallbackExecutor = executor; + mMessageCallback = messageCallback; + return this; + } + + /** + * Add a service to the available services from this endpoint. The {@link HubServiceInfo} + * object can be built with {@link HubServiceInfo.Builder}. + */ + @NonNull + public Builder setServiceInfoCollection( + @NonNull Collection<HubServiceInfo> hubServiceInfos) { + // Make a copy first + mServiceInfos = new ArrayList<>(hubServiceInfos); + return this; + } + + /** Build the {@link HubEndpoint} object. */ + @NonNull + public HubEndpoint build() { + return new HubEndpoint( + new HubEndpointInfo(mPackageName, mVersion, mTag, mServiceInfos), + mLifecycleCallback, + mLifecycleCallbackExecutor, + mMessageCallback, + mMessageCallbackExecutor); + } + } +} diff --git a/core/java/android/hardware/contexthub/HubEndpointInfo.aidl b/core/java/android/hardware/contexthub/HubEndpointInfo.aidl new file mode 100644 index 000000000000..025b2b1f685a --- /dev/null +++ b/core/java/android/hardware/contexthub/HubEndpointInfo.aidl @@ -0,0 +1,20 @@ +/* + * 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 android.hardware.contexthub; + +/** @hide */ +parcelable HubEndpointInfo; diff --git a/core/java/android/hardware/contexthub/HubEndpointInfo.java b/core/java/android/hardware/contexthub/HubEndpointInfo.java new file mode 100644 index 000000000000..b1d55239ac43 --- /dev/null +++ b/core/java/android/hardware/contexthub/HubEndpointInfo.java @@ -0,0 +1,330 @@ +/* + * 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 android.hardware.contexthub; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.chre.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Parcelable representing an endpoint from ContextHub or VendorHub. + * + * <p>HubEndpointInfo contains information about an endpoint, including its name, tag and other + * information. A HubEndpointInfo object can be used to accurately identify a specific endpoint. + * Application can use this object to identify and describe an endpoint. + * + * <p>See: {@link android.hardware.location.ContextHubManager#findEndpoints} for how to retrieve + * {@link HubEndpointInfo} for endpoints on a hub. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public final class HubEndpointInfo implements Parcelable { + /** + * A unique identifier for one endpoint. A unique identifier for one endpoint consists of two + * parts: (1) a unique long number for a hub and (2) a long number for the endpoint, unique + * within a hub. This class overrides equality methods and can be used to compare if two + * endpoints are the same. + */ + public static class HubEndpointIdentifier { + private final long mEndpointId; + private final long mHubId; + + /** @hide */ + public HubEndpointIdentifier(long hubId, long endpointId) { + mEndpointId = endpointId; + mHubId = hubId; + } + + /** @hide */ + public HubEndpointIdentifier(android.hardware.contexthub.EndpointId halEndpointId) { + mEndpointId = halEndpointId.id; + mHubId = halEndpointId.hubId; + } + + /** Get the endpoint portion of the identifier. */ + public long getEndpoint() { + return mEndpointId; + } + + /** Get the hub portion of the identifier. */ + public long getHub() { + return mHubId; + } + + /** + * Create an invalid endpoint id, to represent endpoint that are not yet registered with the + * HAL. + * + * @hide + */ + public static HubEndpointIdentifier invalid() { + return new HubEndpointIdentifier( + android.hardware.contexthub.HubInfo.HUB_ID_INVALID, + android.hardware.contexthub.EndpointId.ENDPOINT_ID_INVALID); + } + + @Override + public int hashCode() { + return Objects.hash(mEndpointId, mHubId); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof HubEndpointIdentifier other)) { + return false; + } + if (other.mHubId != mHubId) { + return false; + } + return other.mEndpointId == mEndpointId; + } + } + + /** This endpoint is from the Android framework */ + public static final int TYPE_FRAMEWORK = 1; + + /** This endpoint is from an Android app */ + public static final int TYPE_APP = 2; + + /** This endpoint is from an Android native program. */ + public static final int TYPE_NATIVE = 3; + + /** This endpoint is from a nanoapp. */ + public static final int TYPE_NANOAPP = 4; + + /** This endpoint is a generic endpoint served by a hub (not from a nanoapp). */ + public static final int TYPE_HUB_ENDPOINT = 5; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + TYPE_FRAMEWORK, + TYPE_APP, + TYPE_NATIVE, + TYPE_NANOAPP, + TYPE_HUB_ENDPOINT, + }) + public @interface EndpointType {} + + private final HubEndpointIdentifier mId; + @EndpointType private final int mType; + private final String mName; + private final int mVersion; + @Nullable private final String mTag; + + @NonNull private final List<String> mRequiredPermissions; + @NonNull private final List<HubServiceInfo> mHubServiceInfos; + + /** @hide */ + public HubEndpointInfo(android.hardware.contexthub.EndpointInfo endpointInfo) { + mId = new HubEndpointIdentifier(endpointInfo.id.hubId, endpointInfo.id.id); + mType = endpointInfo.type; + mName = endpointInfo.name; + mVersion = endpointInfo.version; + mTag = endpointInfo.tag; + mRequiredPermissions = Arrays.asList(endpointInfo.requiredPermissions); + mHubServiceInfos = new ArrayList<>(endpointInfo.services.length); + for (int i = 0; i < endpointInfo.services.length; i++) { + mHubServiceInfos.set(i, new HubServiceInfo(endpointInfo.services[i])); + } + } + + /** @hide */ + public HubEndpointInfo( + String name, + int version, + @Nullable String tag, + @NonNull List<HubServiceInfo> hubServiceInfos) { + mId = HubEndpointIdentifier.invalid(); + mType = TYPE_APP; + mName = name; + mVersion = version; + mTag = tag; + mRequiredPermissions = Collections.emptyList(); + mHubServiceInfos = hubServiceInfos; + } + + private HubEndpointInfo(Parcel in) { + long hubId = in.readLong(); + long endpointId = in.readLong(); + mId = new HubEndpointIdentifier(hubId, endpointId); + mType = in.readInt(); + mName = in.readString(); + mVersion = in.readInt(); + mTag = in.readString(); + mRequiredPermissions = new ArrayList<>(); + in.readStringList(mRequiredPermissions); + mHubServiceInfos = new ArrayList<>(); + in.readTypedList(mHubServiceInfos, HubServiceInfo.CREATOR); + } + + /** Parcel implementation details */ + @Override + public int describeContents() { + int flags = 0; + for (HubServiceInfo serviceInfo : mHubServiceInfos) { + flags |= serviceInfo.describeContents(); + } + return flags; + } + + /** Parcel implementation details */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeLong(mId.getHub()); + dest.writeLong(mId.getEndpoint()); + dest.writeInt(mType); + dest.writeString(mName); + dest.writeInt(mVersion); + dest.writeString(mTag); + dest.writeStringList(mRequiredPermissions); + dest.writeTypedList(mHubServiceInfos, flags); + } + + /** Get a unique identifier for this endpoint. */ + @NonNull + public HubEndpointIdentifier getIdentifier() { + return mId; + } + + /** + * Get the type of this endpoint. Application may use this field to get more information about + * who registered this endpoint for diagnostic purposes. + * + * <p>Type can be one of {@link HubEndpointInfo#TYPE_APP}, {@link + * HubEndpointInfo#TYPE_FRAMEWORK}, {@link HubEndpointInfo#TYPE_NANOAPP}, {@link + * HubEndpointInfo#TYPE_NATIVE} or {@link HubEndpointInfo#TYPE_HUB_ENDPOINT}. + */ + public int getType() { + return mType; + } + + /** Get the human-readable name of this endpoint (for debugging purposes). */ + @NonNull + public String getName() { + return mName; + } + + /** + * Get the version of this endpoint. + * + * <p>Monotonically increasing version number. The two sides of an endpoint session can use this + * version number to identify the other side and determine compatibility with each other. The + * interpretation of the version number is specific to the implementation of an endpoint. + * + * <p>The version number should not be used to compare endpoints implementation freshness for + * different endpoint types. + * + * <p>Depending on type of the endpoint, the following values (and formats) are used: + * + * <ol> + * <li>{@link #TYPE_FRAMEWORK}: android.os.Build.VERSION.SDK_INT_FULL + * <li>{@link #TYPE_APP}: versionCode + * <li>{@link #TYPE_NATIVE}: unspecified format (supplied by endpoint code) + * <li>{@link #TYPE_NANOAPP}: nanoapp version, typically following 0xMMmmpppp scheme where MM + * = major version, mm = minor version, pppp = patch version + * <li>{@link #TYPE_HUB_ENDPOINT}: unspecified format (supplied by endpoint code), following + * nanoapp versioning scheme is recommended + * </ol> + */ + public int getVersion() { + return mVersion; + } + + /** + * Get the tag that further identifies the submodule that created this endpoint. For example, a + * single application could provide multiple endpoints. These endpoints will share the same + * name, but will have different tags. This tag can be used to identify the submodule within the + * application that provided the endpoint. + */ + @Nullable + public String getTag() { + return mTag; + } + + /** + * Get the list of required permissions in order to talk to this endpoint. + * + * <p>This list is enforced by the Context Hub Service. The app would need to have the required + * permissions list to open a session with this particular endpoint. Otherwise this will be + * rejected by as permission failures. + * + * <p>This is mostly for allowing app to check what permission it needs first internally. App + * will need to request permissions grant at runtime if not already granted. See {@link + * android.content.Context#checkPermission} for more details. + * + * <p>See {@link android.Manifest.permission} for a list of standard Android permissions as + * possible values. + */ + @SuppressLint("RequiresPermission") + @NonNull + public Collection<String> getRequiredPermissions() { + return Collections.unmodifiableList(mRequiredPermissions); + } + + /** + * Get the list of services provided by this endpoint. + * + * <p>See {@link HubServiceInfo} for more information. + */ + @NonNull + public Collection<HubServiceInfo> getServiceInfoCollection() { + return Collections.unmodifiableList(mHubServiceInfos); + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + out.append("Endpoint [0x"); + out.append(Long.toHexString(mId.getEndpoint())); + out.append("@ Hub 0x"); + out.append(Long.toHexString(mId.getHub())); + out.append("] Name="); + out.append(mName); + out.append(", Tag="); + out.append(mTag); + return out.toString(); + } + + public static final @android.annotation.NonNull Creator<HubEndpointInfo> CREATOR = + new Creator<>() { + public HubEndpointInfo createFromParcel(Parcel in) { + return new HubEndpointInfo(in); + } + + public HubEndpointInfo[] newArray(int size) { + return new HubEndpointInfo[size]; + } + }; +} diff --git a/core/java/android/hardware/contexthub/HubEndpointSession.java b/core/java/android/hardware/contexthub/HubEndpointSession.java new file mode 100644 index 000000000000..cf952cbdbfdc --- /dev/null +++ b/core/java/android/hardware/contexthub/HubEndpointSession.java @@ -0,0 +1,170 @@ +/* + * 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 android.hardware.contexthub; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.chre.flags.Flags; +import android.hardware.location.ContextHubTransaction; +import android.hardware.location.ContextHubTransactionHelper; +import android.hardware.location.IContextHubTransactionCallback; +import android.util.CloseGuard; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * An object representing a communication session between two different hub endpoints. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public class HubEndpointSession implements AutoCloseable { + private final CloseGuard mCloseGuard = new CloseGuard(); + + private final int mId; + + @NonNull private final HubEndpoint mHubEndpoint; + @NonNull private final HubEndpointInfo mInitiator; + @NonNull private final HubEndpointInfo mDestination; + @Nullable private final HubServiceInfo mServiceInfo; + + private final AtomicBoolean mIsClosed = new AtomicBoolean(true); + + /** @hide */ + HubEndpointSession( + int id, + @NonNull HubEndpoint hubEndpoint, + @NonNull HubEndpointInfo destination, + @NonNull HubEndpointInfo initiator, + @Nullable HubServiceInfo serviceInfo) { + mId = id; + mHubEndpoint = hubEndpoint; + mDestination = destination; + mInitiator = initiator; + mServiceInfo = serviceInfo; + } + + /** + * Send a message to the peer endpoint in this session. + * + * @param message The message object constructed with {@link HubMessage#createMessage}. + * @return For messages that does not require a response, the transaction will immediately + * complete. For messages that requires a response, the transaction will complete after + * receiving the response for the message. + */ + @NonNull + public ContextHubTransaction<Void> sendMessage(@NonNull HubMessage message) { + if (mIsClosed.get()) { + throw new IllegalStateException("Session is already closed."); + } + + boolean isResponseRequired = message.getDeliveryParams().isResponseRequired(); + ContextHubTransaction<Void> ret = + new ContextHubTransaction<>( + isResponseRequired + ? ContextHubTransaction.TYPE_HUB_MESSAGE_REQUIRES_RESPONSE + : ContextHubTransaction.TYPE_HUB_MESSAGE_DEFAULT); + if (!isResponseRequired) { + // If the message doesn't require acknowledgement, respond with success immediately + // TODO(b/379162322): Improve handling of synchronous failures. + mHubEndpoint.sendMessage(this, message, null); + ret.setResponse( + new ContextHubTransaction.Response<>( + ContextHubTransaction.RESULT_SUCCESS, null)); + } else { + IContextHubTransactionCallback callback = + ContextHubTransactionHelper.createTransactionCallback(ret); + // Sequence number will be assigned at the service + mHubEndpoint.sendMessage(this, message, callback); + } + return ret; + } + + /** @hide */ + public int getId() { + return mId; + } + + /** @hide */ + public void setOpened() { + mIsClosed.set(false); + mCloseGuard.open("close"); + } + + /** @hide */ + public void setClosed() { + mIsClosed.set(true); + mCloseGuard.close(); + } + + /** + * Closes the connection for this session between an endpoint and the Context Hub Service. + * + * <p>When this function is invoked, the messaging associated with this session is invalidated. + * All futures messages targeted for this client are dropped. + */ + public void close() { + if (!mIsClosed.getAndSet(true)) { + mCloseGuard.close(); + mHubEndpoint.closeSession(this); + } + } + + /** + * Get the {@link HubServiceInfo} associated with this session. Null value indicates that there + * is no service associated to this session. + * + * <p>For hub initiated sessions, the object was previously used in as an argument for open + * request in {@link IHubEndpointLifecycleCallback#onSessionOpenRequest}. + * + * <p>For app initiated sessions, the object was previously used in an open request in {@link + * android.hardware.location.ContextHubManager#openSession} + */ + @Nullable + public HubServiceInfo getServiceInfo() { + return mServiceInfo; + } + + @Override + public String toString() { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Session ["); + stringBuilder.append(mId); + stringBuilder.append("]: ["); + stringBuilder.append(mInitiator); + stringBuilder.append("]->["); + stringBuilder.append(mDestination); + stringBuilder.append("]"); + return stringBuilder.toString(); + } + + /** @hide */ + protected void finalize() throws Throwable { + try { + // Note that guard could be null if the constructor threw. + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + close(); + } finally { + super.finalize(); + } + } +} diff --git a/core/java/android/hardware/contexthub/HubEndpointSessionResult.java b/core/java/android/hardware/contexthub/HubEndpointSessionResult.java new file mode 100644 index 000000000000..1f2bdb985008 --- /dev/null +++ b/core/java/android/hardware/contexthub/HubEndpointSessionResult.java @@ -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 android.hardware.contexthub; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.chre.flags.Flags; + +/** + * Return type of {@link IHubEndpointLifecycleCallback#onSessionOpenRequest}. The value determines + * whether a open session request from the remote is accepted or not. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public class HubEndpointSessionResult { + private final boolean mAccepted; + + @Nullable private final String mReason; + + private HubEndpointSessionResult(boolean accepted, @Nullable String reason) { + mAccepted = accepted; + mReason = reason; + } + + /** + * Retrieve the decision of the session request. + * + * @return Whether a session request was accepted or not, previously set with {@link #accept()} + * or {@link #reject(String)}. + */ + public boolean isAccepted() { + return mAccepted; + } + + /** + * Retrieve the decision of the session request. + * + * @return The reason previously set in {@link #reject(String)}. If the result was {@link + * #accept()}, the reason will be null. + */ + @Nullable + public String getReason() { + return mReason; + } + + /** Accept the request. */ + @NonNull + public static HubEndpointSessionResult accept() { + return new HubEndpointSessionResult(true, null); + } + + /** + * Reject the request with a reason. + * + * @param reason Reason why the request was rejected, for diagnostic purposes. + */ + @NonNull + public static HubEndpointSessionResult reject(@NonNull String reason) { + return new HubEndpointSessionResult(false, reason); + } +} diff --git a/core/java/android/hardware/contexthub/HubMessage.aidl b/core/java/android/hardware/contexthub/HubMessage.aidl new file mode 100644 index 000000000000..86afce233062 --- /dev/null +++ b/core/java/android/hardware/contexthub/HubMessage.aidl @@ -0,0 +1,22 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.contexthub; + +/** + * @hide + */ +parcelable HubMessage; diff --git a/core/java/android/hardware/contexthub/HubMessage.java b/core/java/android/hardware/contexthub/HubMessage.java new file mode 100644 index 000000000000..dc8a8c52ea55 --- /dev/null +++ b/core/java/android/hardware/contexthub/HubMessage.java @@ -0,0 +1,289 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.contexthub; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.chre.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; + +import libcore.util.HexEncoding; + +import java.util.Arrays; +import java.util.Objects; + +/** + * A class describing general messages send through the Context Hub Service. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public final class HubMessage implements Parcelable { + private static final int DEBUG_LOG_NUM_BYTES = 16; + + private final int mMessageType; + private final byte[] mMessageBody; + + private final DeliveryParams mDeliveryParams; + private int mMessageSequenceNumber; + + /** + * Configurable options for message delivery. This option can be passed into {@link + * HubEndpointSession#sendMessage} to specify the behavior of message delivery. + */ + public static class DeliveryParams { + private boolean mResponseRequired; + + private DeliveryParams(boolean responseRequired) { + mResponseRequired = responseRequired; + } + + /** Get the acknowledgement requirement. */ + public boolean isResponseRequired() { + return mResponseRequired; + } + + /** + * Set the response requirement for a message. Message sent with this option will have a + * {@link android.hardware.location.ContextHubTransaction.Response} when the peer received + * the message. Default is false. + */ + @NonNull + public DeliveryParams setResponseRequired(boolean required) { + mResponseRequired = required; + return this; + } + + /** Construct a default delivery option. */ + @NonNull + public static DeliveryParams makeBasic() { + return new DeliveryParams(false); + } + + @Override + public String toString() { + StringBuilder out = new StringBuilder(); + out.append("DeliveryParams["); + out.append("responseRequired = ").append(mResponseRequired); + out.append("]"); + return out.toString(); + } + + @Override + public int hashCode() { + return Objects.hash(mResponseRequired); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj instanceof DeliveryParams other) { + return other.mResponseRequired == mResponseRequired; + } + + return false; + } + } + + private HubMessage(int messageType, byte[] messageBody, DeliveryParams deliveryParams) { + mMessageType = messageType; + mMessageBody = messageBody; + mDeliveryParams = deliveryParams; + } + + /** + * Creates a HubMessage object to send to through an endpoint. + * + * @param messageType the endpoint & service dependent message type + * @param messageBody the byte array message contents + * @return the HubMessage object + */ + @NonNull + public static HubMessage createMessage(int messageType, @NonNull byte[] messageBody) { + return new HubMessage(messageType, messageBody, DeliveryParams.makeBasic()); + } + + /** + * Creates a HubMessage object to send to through an endpoint. + * + * @param messageType the endpoint & service dependent message type + * @param messageBody the byte array message contents + * @param deliveryParams The message delivery parameters. See {@link HubMessage.DeliveryParams} + * for more details. + * @return the HubMessage object + */ + @NonNull + public static HubMessage createMessage( + int messageType, @NonNull byte[] messageBody, @NonNull DeliveryParams deliveryParams) { + return new HubMessage(messageType, messageBody, deliveryParams); + } + + /** + * Retrieve the message type. + * + * @return the type of the message + */ + public int getMessageType() { + return mMessageType; + } + + /** + * Retrieve the body of the message. The body can be an empty byte array. + * + * @return the byte array contents of the message + */ + @NonNull + public byte[] getMessageBody() { + return mMessageBody; + } + + /** + * Retrieve the {@link DeliveryParams} object specifying the behavior of message delivery. + * + * @hide + */ + public DeliveryParams getDeliveryParams() { + return mDeliveryParams; + } + + /** + * Assign a message sequence number. This should only be called by the system service. + * + * @hide + */ + public void setMessageSequenceNumber(int messageSequenceNumber) { + mMessageSequenceNumber = messageSequenceNumber; + } + + /** + * Returns the message sequence number. The default value is 0. + * + * @return the message sequence number of the message + * @hide + */ + public int getMessageSequenceNumber() { + return mMessageSequenceNumber; + } + + private HubMessage(@NonNull Parcel in) { + mMessageType = in.readInt(); + + int msgSize = in.readInt(); + mMessageBody = new byte[msgSize]; + in.readByteArray(mMessageBody); + + mDeliveryParams = DeliveryParams.makeBasic(); + mDeliveryParams.setResponseRequired(in.readInt() == 1); + mMessageSequenceNumber = in.readInt(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mMessageType); + + out.writeInt(mMessageBody.length); + out.writeByteArray(mMessageBody); + + out.writeInt(mDeliveryParams.isResponseRequired() ? 1 : 0); + out.writeInt(mMessageSequenceNumber); + } + + public static final @NonNull Creator<HubMessage> CREATOR = + new Creator<>() { + @Override + public HubMessage createFromParcel(Parcel in) { + return new HubMessage(in); + } + + @Override + public HubMessage[] newArray(int size) { + return new HubMessage[size]; + } + }; + + @NonNull + @Override + public String toString() { + int length = mMessageBody.length; + + StringBuilder out = new StringBuilder(); + out.append("HubMessage[type = ").append(mMessageType); + out.append(", length = ").append(mMessageBody.length); + out.append(", messageSequenceNumber = ").append(mMessageSequenceNumber); + out.append(", deliveryParams = ").append(mDeliveryParams); + out.append("]("); + + if (length > 0) { + out.append("data = 0x"); + } + for (int i = 0; i < Math.min(length, DEBUG_LOG_NUM_BYTES); i++) { + out.append(HexEncoding.encodeToString(mMessageBody[i], true /* upperCase */)); + + if ((i + 1) % 4 == 0) { + out.append(" "); + } + } + if (length > DEBUG_LOG_NUM_BYTES) { + out.append("..."); + } + out.append(")"); + + return out.toString(); + } + + @Override + public boolean equals(@Nullable Object object) { + if (object == this) { + return true; + } + + boolean isEqual = false; + if (object instanceof HubMessage other) { + isEqual = + (other.getMessageType() == mMessageType) + && Arrays.equals(other.getMessageBody(), mMessageBody) + && (other.getDeliveryParams().equals(mDeliveryParams)) + && (other.getMessageSequenceNumber() == mMessageSequenceNumber); + } + + return isEqual; + } + + @Override + public int hashCode() { + if (!Flags.fixApiCheck()) { + return super.hashCode(); + } + + return Objects.hash( + mMessageType, + Arrays.hashCode(mMessageBody), + mDeliveryParams, + mMessageSequenceNumber); + } +} diff --git a/core/java/android/hardware/contexthub/HubServiceInfo.aidl b/core/java/android/hardware/contexthub/HubServiceInfo.aidl new file mode 100644 index 000000000000..98b1bbab8b60 --- /dev/null +++ b/core/java/android/hardware/contexthub/HubServiceInfo.aidl @@ -0,0 +1,22 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.contexthub; + +/** + * @hide + */ +parcelable HubServiceInfo; diff --git a/core/java/android/hardware/contexthub/HubServiceInfo.java b/core/java/android/hardware/contexthub/HubServiceInfo.java new file mode 100644 index 000000000000..c7fe77c4a0f1 --- /dev/null +++ b/core/java/android/hardware/contexthub/HubServiceInfo.java @@ -0,0 +1,263 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.contexthub; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.chre.flags.Flags; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.ParcelableHolder; + +import androidx.annotation.NonNull; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collection; +import java.util.Objects; + +/** + * A class describing services provided by endpoints. + * + * <p>An endpoint can provide zero or more service. See {@link + * HubEndpoint.Builder#setServiceInfoCollection(Collection)} and {@link + * HubEndpointInfo#getServiceInfoCollection()}. + * + * <p>An endpoint session can be service-less or associated to one service.See {@link + * HubEndpointSession#getServiceInfo()}. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public final class HubServiceInfo implements Parcelable { + /** Customized format for messaging. Fully customized and opaque messaging format. */ + public static final int FORMAT_CUSTOM = 0; + + /** + * Binder-based messaging. The host endpoint is defining this service in Stable AIDL. Messages + * between endpoints that uses this service will be using the binder marhsalling format. + */ + public static final int FORMAT_AIDL = 1; + + /** + * Pigweed RPC messaging with Protobuf. This endpoint is a Pigweed RPC. Messages between + * endpoints will use Pigweed RPC marshalling format (protobuf). + */ + public static final int FORMAT_PW_RPC_PROTOBUF = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + FORMAT_CUSTOM, + FORMAT_AIDL, + FORMAT_PW_RPC_PROTOBUF, + }) + public @interface ServiceFormat {} + + @NonNull private final String mServiceDescriptor; + + @ServiceFormat private final int mFormat; + private final int mMajorVersion; + private final int mMinorVersion; + + @NonNull private final ParcelableHolder mExtendedInfo; + + /** @hide */ + public HubServiceInfo(android.hardware.contexthub.Service service) { + mServiceDescriptor = service.serviceDescriptor; + mFormat = service.format; + mMajorVersion = service.majorVersion; + mMinorVersion = service.minorVersion; + mExtendedInfo = service.extendedInfo; + } + + private HubServiceInfo(Parcel in) { + mServiceDescriptor = Objects.requireNonNull(in.readString()); + mFormat = in.readInt(); + mMajorVersion = in.readInt(); + mMinorVersion = in.readInt(); + mExtendedInfo = ParcelableHolder.CREATOR.createFromParcel(in); + } + + public HubServiceInfo( + @NonNull String serviceDescriptor, + @ServiceFormat int format, + int majorVersion, + int minorVersion, + @NonNull ParcelableHolder extendedInfo) { + mServiceDescriptor = serviceDescriptor; + mFormat = format; + mMajorVersion = majorVersion; + mMinorVersion = minorVersion; + mExtendedInfo = extendedInfo; + } + + /** Get the unique identifier of this service. See {@link Builder} for more information. */ + @NonNull + public String getServiceDescriptor() { + return mServiceDescriptor; + } + + /** + * Get the type of the service. + * + * <p>The value can be one of {@link HubServiceInfo#FORMAT_CUSTOM}, {@link + * HubServiceInfo#FORMAT_AIDL} or {@link HubServiceInfo#FORMAT_PW_RPC_PROTOBUF}. + */ + public int getFormat() { + return mFormat; + } + + /** Get the major version of this service. */ + public int getMajorVersion() { + return mMajorVersion; + } + + /** Get the minor version of this service. */ + public int getMinorVersion() { + return mMinorVersion; + } + + /** Get the {@link ParcelableHolder} for the extended information about the service. */ + @NonNull + public ParcelableHolder getExtendedInfo() { + return mExtendedInfo; + } + + /** Parcel implementation details */ + @Override + public int describeContents() { + // Passthrough describeContents flags for mExtendedInfo because we don't have FD otherwise. + return mExtendedInfo.describeContents(); + } + + /** Parcel implementation details */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mServiceDescriptor); + dest.writeInt(mFormat); + dest.writeInt(mMajorVersion); + dest.writeInt(mMinorVersion); + mExtendedInfo.writeToParcel(dest, flags); + } + + /** Builder for a {@link HubServiceInfo} object. */ + public static final class Builder { + @NonNull private final String mServiceDescriptor; + + @ServiceFormat private final int mFormat; + private final int mMajorVersion; + private final int mMinorVersion; + + private final ParcelableHolder mExtendedInfo = + new ParcelableHolder(Parcelable.PARCELABLE_STABILITY_VINTF); + + /** + * Create a builder for {@link HubServiceInfo} with a service descriptor. + * + * <p>Service descriptor should uniquely identify the interface (scoped to type). Convention + * of the descriptor depend on interface type. + * + * <p>Examples: + * + * <ol> + * <li>AOSP-defined AIDL: android.hardware.something.IFoo/default + * <li>Vendor-defined AIDL: com.example.something.IBar/default + * <li>Pigweed RPC with Protobuf: com.example.proto.ExampleService + * </ol> + * + * @param serviceDescriptor The service descriptor. + * @param format One of {@link HubServiceInfo#FORMAT_CUSTOM}, {@link + * HubServiceInfo#FORMAT_AIDL} or {@link HubServiceInfo#FORMAT_PW_RPC_PROTOBUF}. + * @param majorVersion Breaking changes should be a major version bump. + * @param minorVersion Monotonically increasing minor version. + * @throws IllegalArgumentException if one or more fields are not valid. + */ + public Builder( + @NonNull String serviceDescriptor, + @ServiceFormat int format, + int majorVersion, + int minorVersion) { + if (format != FORMAT_CUSTOM + && format != FORMAT_AIDL + && format != FORMAT_PW_RPC_PROTOBUF) { + throw new IllegalArgumentException("Invalid format type."); + } + mFormat = format; + + if (majorVersion < 0) { + throw new IllegalArgumentException( + "Major version cannot be set to negative number."); + } + mMajorVersion = majorVersion; + + if (minorVersion < 0) { + throw new IllegalArgumentException( + "Minor version cannot be set to negative number."); + } + mMinorVersion = minorVersion; + + if (serviceDescriptor.isBlank()) { + throw new IllegalArgumentException("Invalid service descriptor."); + } + mServiceDescriptor = serviceDescriptor; + } + + /** + * Set the extended information of this service. + * + * @param extendedInfo Parcelable with extended information about this service. The + * parcelable needs to have at least VINTF stability. Null can be used to clear a + * previously set value. + * @throws android.os.BadParcelableException if the parcelable cannot be used. + */ + @NonNull + public Builder setExtendedInfo(@Nullable Parcelable extendedInfo) { + mExtendedInfo.setParcelable(extendedInfo); + return this; + } + + /** + * Build the {@link HubServiceInfo} object. + * + * @throws IllegalStateException if the Builder is missing required info. + */ + @NonNull + public HubServiceInfo build() { + if (mMajorVersion < 0 || mMinorVersion < 0) { + throw new IllegalStateException("Major and minor version must be set."); + } + return new HubServiceInfo( + mServiceDescriptor, mFormat, mMajorVersion, mMinorVersion, mExtendedInfo); + } + } + + /** Parcel implementation details */ + @NonNull + public static final Parcelable.Creator<HubServiceInfo> CREATOR = + new Parcelable.Creator<>() { + public HubServiceInfo createFromParcel(Parcel in) { + return new HubServiceInfo(in); + } + + public HubServiceInfo[] newArray(int size) { + return new HubServiceInfo[size]; + } + }; +} diff --git a/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl new file mode 100644 index 000000000000..1c98b4b3f4f5 --- /dev/null +++ b/core/java/android/hardware/contexthub/IContextHubEndpoint.aidl @@ -0,0 +1,90 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.contexthub; + +import android.hardware.contexthub.HubEndpointInfo; +import android.hardware.contexthub.HubMessage; +import android.hardware.contexthub.HubServiceInfo; +import android.hardware.location.IContextHubTransactionCallback; + +/** + * @hide + */ +interface IContextHubEndpoint { + /** + * Retrieve the up-to-date EndpointInfo, with assigned endpoint id. + */ + HubEndpointInfo getAssignedHubEndpointInfo(); + + /** + * Request system service to open a session with a specific destination. + * + * @param destination A valid HubEndpointInfo representing the destination. + * + * @throws IllegalArgumentException If the HubEndpointInfo is not valid. + * @throws IllegalStateException If there are too many opened sessions. + */ + int openSession(in HubEndpointInfo destination, in @nullable HubServiceInfo serviceInfo); + + /** + * Request system service to close a specific session + * + * @param sessionId An integer identifying the session, assigned by system service + * @param reason An integer identifying the reason + * + * @throws IllegalStateException If the session wasn't opened. + */ + void closeSession(int sessionId, int reason); + + /** + * Callback when a session is opened. This callback is the status callback for a previous + * IContextHubEndpointCallback.onSessionOpenRequest(). + * + * @param sessionId The integer representing the communication session, previously set in + * onSessionOpenRequest(). + * + * @throws IllegalStateException If the session wasn't opened. + */ + void openSessionRequestComplete(int sessionId); + + /** + * Unregister this endpoint from the HAL, invalidate the EndpointInfo previously assigned. + */ + void unregister(); + + /** + * Send a message parcelable to system service for a specific session. + * + * @param sessionId The integer representing the communication session, previously set in + * IContextHubEndpoint.openSession(). This id is assigned by the HAL. + * @param message The HubMessage parcelable that represents the message and its delivery options. + * @param transactionCallback Nullable. If the hub message requires a reply, the transactionCallback + * will be set to non-null. + */ + void sendMessage(int sessionId, in HubMessage message, + in @nullable IContextHubTransactionCallback transactionCallback); + + /** + * Send a message delivery status to system service for a specific message + * + * @param sessionId The integer representing the communication session, previously set in + * IContextHubEndpoint.openSession(). This id is assigned by the HAL. + * @param messageSeqNumber The message sequence number, this should match a previously received HubMessage. + * @param errorCode The message delivery status detail. + */ + void sendMessageDeliveryStatus(int sessionId, int messageSeqNumber, byte errorCode); +} diff --git a/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl b/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl new file mode 100644 index 000000000000..1ae5fb9d28c1 --- /dev/null +++ b/core/java/android/hardware/contexthub/IContextHubEndpointCallback.aidl @@ -0,0 +1,61 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.contexthub; + +import android.hardware.contexthub.HubEndpointInfo; +import android.hardware.contexthub.HubMessage; +import android.hardware.contexthub.HubServiceInfo; + +/** + * @hide + */ +oneway interface IContextHubEndpointCallback { + /** + * Request from system service to open a session, requested by a specific initiator. + * + * @param sessionId An integer identifying the session, assigned by the initiator + * @param initiator HubEndpointInfo representing the requester + * @param serviceInfo Nullable HubServiceInfo representing the service associated with this session + */ + void onSessionOpenRequest(int sessionId, in HubEndpointInfo initiator, in @nullable HubServiceInfo serviceInfo); + + /** + * Request from system service to close a specific session + * + * @param sessionId An integer identifying the session + * @param reason An integer identifying the reason + */ + void onSessionClosed(int sessionId, int reason); + + /** + * Notifies the system service that the session requested by IContextHubEndpoint.openSession + * is ready to use. + * + * @param sessionId The integer representing the communication session, previously set in + * IContextHubEndpoint.openSession(). This id is assigned by the HAL. + */ + void onSessionOpenComplete(int sessionId); + + /** + * Message notification from system service for a specific session + + * @param sessionId The integer representing the communication session, previously set in + * IContextHubEndpoint.openSession(). This id is assigned by the HAL. + * @param message The HubMessage parcelable that represents the message. + */ + void onMessageReceived(int sessionId, in HubMessage message); +} diff --git a/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java new file mode 100644 index 000000000000..46884393b49b --- /dev/null +++ b/core/java/android/hardware/contexthub/IHubEndpointLifecycleCallback.java @@ -0,0 +1,82 @@ +/* + * 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 android.hardware.contexthub; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.chre.flags.Flags; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Interface for listening to lifecycle events of a hub endpoint. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public interface IHubEndpointLifecycleCallback { + /** Unknown reason. */ + int REASON_UNSPECIFIED = 0; + + /** The peer rejected the request to open this endpoint session. */ + int REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED = 3; + + /** The peer closed this endpoint session. */ + int REASON_CLOSE_ENDPOINT_SESSION_REQUESTED = 4; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + REASON_UNSPECIFIED, + REASON_OPEN_ENDPOINT_SESSION_REQUEST_REJECTED, + REASON_CLOSE_ENDPOINT_SESSION_REQUESTED, + }) + @interface EndpointLifecycleReason {} + + /** + * Called when an endpoint is requesting a session be opened with another endpoint. + * + * @param requester The {@link HubEndpointInfo} object representing the requester + * @param serviceInfo The {@link HubServiceInfo} object representing the service associated with + * this session. Null indicates that there is no service associated with this session. + */ + @NonNull + HubEndpointSessionResult onSessionOpenRequest( + @NonNull HubEndpointInfo requester, @Nullable HubServiceInfo serviceInfo); + + /** + * Called when a communication session is opened and ready to be used. + * + * @param session The {@link HubEndpointSession} object that can be used for communication + */ + void onSessionOpened(@NonNull HubEndpointSession session); + + /** + * Called when a communication session is requested to be closed, or the peer endpoint rejected + * the session open request. + * + * @param session The {@link HubEndpointSession} object that is now closed and shouldn't be + * used. + * @param reason The reason why this session was closed. + */ + void onSessionClosed(@NonNull HubEndpointSession session, @EndpointLifecycleReason int reason); +} diff --git a/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java b/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java new file mode 100644 index 000000000000..fde7017b5e76 --- /dev/null +++ b/core/java/android/hardware/contexthub/IHubEndpointMessageCallback.java @@ -0,0 +1,45 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.contexthub; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.chre.flags.Flags; + +/** + * An interface used to deliver messages to an opened endpoint session. + * + * <p>This interface can be attached to an endpoint through {@link + * HubEndpoint.Builder#setMessageCallback} method. Methods in this interface will only be called + * when the endpoint is currently registered and has an open session. The endpoint will receive + * session lifecycle callbacks through {@link IHubEndpointLifecycleCallback}. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_OFFLOAD_API) +public interface IHubEndpointMessageCallback { + /** + * Callback interface for receiving messages for a particular endpoint session. + * + * @param session The session this message is sent through. Previously specified in a {@link + * IHubEndpointLifecycleCallback#onSessionOpened(HubEndpointSession)} call. + * @param message The {@link HubMessage} object representing a message received by the endpoint + * that registered this callback interface. This message is constructed by the + */ + void onMessageReceived(@NonNull HubEndpointSession session, @NonNull HubMessage message); +} diff --git a/core/java/android/hardware/contexthub/OWNERS b/core/java/android/hardware/contexthub/OWNERS new file mode 100644 index 000000000000..a65a2bf9ee36 --- /dev/null +++ b/core/java/android/hardware/contexthub/OWNERS @@ -0,0 +1,2 @@ +# ContextHub team +file:platform/system/chre:/OWNERS diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index e6a1640781ed..25327a9b1d52 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -61,6 +61,7 @@ import android.view.Surface; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; +import com.android.server.display.feature.flags.Flags; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -102,6 +103,7 @@ public final class DisplayManager { private final WeakDisplayCache mDisplayCache = new WeakDisplayCache(); private int mDisplayIdToMirror = INVALID_DISPLAY; + private AmbientDisplayConfiguration mAmbientDisplayConfiguration; /** * Broadcast receiver that indicates when the Wifi display status changes. @@ -1613,6 +1615,17 @@ public final class DisplayManager { } /** + * Returns whether this device supports Always On Display. + * + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_IS_ALWAYS_ON_AVAILABLE_API) + public boolean isAlwaysOnDisplayCurrentlyAvailable() { + return getAmbientDisplayConfiguration().alwaysOnAvailableForUser(mContext.getUserId()); + } + + /** * Returns whether device supports seamless refresh rate switching. * * Match content frame rate setting has three options: seamless, non-seamless and never. @@ -1674,6 +1687,15 @@ public final class DisplayManager { } } + private AmbientDisplayConfiguration getAmbientDisplayConfiguration() { + synchronized (this) { + if (mAmbientDisplayConfiguration == null) { + mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext); + } + } + return mAmbientDisplayConfiguration; + } + /** * Creates a VirtualDisplay that will mirror the content of displayIdToMirror * @param name The name for the virtual display diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index be710b1328e7..1e66beea42a6 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -17,6 +17,7 @@ package android.hardware.display; +import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM; import static android.hardware.display.DisplayManager.EventFlag; import static android.Manifest.permission.MANAGE_DISPLAYS; import static android.view.Display.HdrCapabilities.HdrType; @@ -188,9 +189,11 @@ public final class DisplayManagerGlobal { } private PropertyInvalidatedCache<Integer, DisplayInfo> mDisplayCache = - new PropertyInvalidatedCache<Integer, DisplayInfo>( - 8, // size of display cache - CACHE_KEY_DISPLAY_INFO_PROPERTY) { + new PropertyInvalidatedCache<>( + new PropertyInvalidatedCache.Args(MODULE_SYSTEM) + .maxEntries(8).api(CACHE_KEY_DISPLAY_INFO_API).isolateUids(false), + CACHE_KEY_DISPLAY_INFO_API, null) { + @Override public DisplayInfo recompute(Integer id) { try { @@ -1514,18 +1517,17 @@ public final class DisplayManagerGlobal { } /** - * Name of the property containing a unique token which changes every time we update the - * system's display configuration. + * The API portion of the key that identifies the unique PropertyInvalidatedCache token which + * changes every time we update the system's display configuration. */ - public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY = - PropertyInvalidatedCache.createSystemCacheKey("display_info"); + private static final String CACHE_KEY_DISPLAY_INFO_API = "display_info"; /** * Invalidates the contents of the display info cache for all applications. Can only * be called by system_server. */ public static void invalidateLocalDisplayInfoCaches() { - PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DISPLAY_INFO_PROPERTY); + PropertyInvalidatedCache.invalidateCache(MODULE_SYSTEM, CACHE_KEY_DISPLAY_INFO_API); } /** diff --git a/core/java/android/hardware/flags/overlayproperties_flags.aconfig b/core/java/android/hardware/flags/flags.aconfig index 6c86108c4034..5ca6c6bed1f0 100644 --- a/core/java/android/hardware/flags/overlayproperties_flags.aconfig +++ b/core/java/android/hardware/flags/flags.aconfig @@ -2,6 +2,15 @@ package: "android.hardware.flags" container: "system" flag { + name: "luts_api" + is_exported: true + is_fixed_read_only: true + namespace: "core_graphics" + description: "public Luts related Apis" + bug: "349667978" +} + +flag { name: "overlayproperties_class_api" is_exported: true namespace: "core_graphics" diff --git a/core/java/android/hardware/input/KeyGestureEvent.java b/core/java/android/hardware/input/KeyGestureEvent.java index 24951c4d516e..711dc3a2cf7c 100644 --- a/core/java/android/hardware/input/KeyGestureEvent.java +++ b/core/java/android/hardware/input/KeyGestureEvent.java @@ -115,12 +115,14 @@ public final class KeyGestureEvent { public static final int KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS = 67; public static final int KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW = 68; public static final int KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW = 69; - public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 70; - public static final int KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE = 71; + public static final int KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW = 70; + public static final int KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW = 71; public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN = 72; public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT = 73; public static final int KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION = 74; public static final int KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK = 75; + public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 76; + public static final int FLAG_CANCELLED = 1; @@ -205,12 +207,13 @@ public final class KeyGestureEvent { KEY_GESTURE_TYPE_TOGGLE_MOUSE_KEYS, KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW, KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW, - KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW, - KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE, + KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW, + KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW, KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN, KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT, KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION, KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK, + KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW }) @Retention(RetentionPolicy.SOURCE) public @interface KeyGestureType { @@ -557,14 +560,6 @@ public final class KeyGestureEvent { return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__DESKTOP_MODE; case KEY_GESTURE_TYPE_MULTI_WINDOW_NAVIGATION: return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MULTI_WINDOW_NAVIGATION; - case KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW: - return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SNAP_LEFT_FREEFORM_WINDOW; - case KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW: - return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__SNAP_RIGHT_FREEFORM_WINDOW; - case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW: - return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__MAXIMIZE_FREEFORM_WINDOW; - case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE: - return FrameworkStatsLog.KEYBOARD_SYSTEMS_EVENT_REPORTED__KEYBOARD_SYSTEM_EVENT__RESTORE_FREEFORM_WINDOW_SIZE; default: return LOG_EVENT_UNSPECIFIED; } @@ -777,10 +772,10 @@ public final class KeyGestureEvent { return "KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW"; case KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW: return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW"; - case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW: - return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW"; - case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE: - return "KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE"; + case KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW: + return "KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW"; + case KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW: + return "KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW"; case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN: return "KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN"; case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT: @@ -789,6 +784,8 @@ public final class KeyGestureEvent { return "KEY_GESTURE_TYPE_TOGGLE_MAGNIFICATION"; case KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK: return "KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK"; + case KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW: + return "KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW"; default: return Integer.toHexString(value); } diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index 4b2f2c218e5a..fee074901c10 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -170,4 +170,11 @@ flag { namespace: "input" description: "Adds key gestures for talkback and magnifier" bug: "375277034" -}
\ No newline at end of file +} + +flag { + name: "can_window_override_power_gesture_api" + namespace: "wallet_integration" + description: "Adds new API in WindowManager class to check if the window can override the power key double tap behavior." + bug: "378736024" + }
\ No newline at end of file diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 494bfc926384..426cd69f76a0 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -34,6 +34,11 @@ import android.chre.flags.Flags; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.contexthub.ErrorCode; +import android.hardware.contexthub.HubDiscoveryInfo; +import android.hardware.contexthub.HubEndpoint; +import android.hardware.contexthub.HubEndpointInfo; +import android.hardware.contexthub.HubServiceInfo; +import android.hardware.contexthub.IHubEndpointLifecycleCallback; import android.os.Handler; import android.os.HandlerExecutor; import android.os.Looper; @@ -42,6 +47,7 @@ import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; @@ -679,6 +685,65 @@ public final class ContextHubManager { } /** + * Find a list of endpoints that matches a specific ID. + * + * @param endpointId Statically generated ID for an endpoint. + * @return A list of {@link HubDiscoveryInfo} objects that represents the result of discovery. + */ + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @NonNull + public List<HubDiscoveryInfo> findEndpoints(long endpointId) { + // TODO(b/379323274): Consider improving these getters to avoid racing with nano app load + // timing. + try { + List<HubEndpointInfo> endpointInfos = mService.findEndpoints(endpointId); + List<HubDiscoveryInfo> results = new ArrayList<>(endpointInfos.size()); + // Wrap with result type + for (HubEndpointInfo endpointInfo : endpointInfos) { + results.add(new HubDiscoveryInfo(endpointInfo)); + } + return results; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Find a list of endpoints that provides a specific service. + * + * @param serviceDescriptor Statically generated ID for an endpoint. + * @return A list of {@link HubDiscoveryInfo} objects that represents the result of discovery. + * @throws IllegalArgumentException if the serviceDescriptor is empty/null. + */ + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @NonNull + public List<HubDiscoveryInfo> findEndpoints(@NonNull String serviceDescriptor) { + // TODO(b/379323274): Consider improving these getters to avoid racing with nano app load + // timing. + if (serviceDescriptor.isBlank()) { + throw new IllegalArgumentException("Invalid service descriptor: " + serviceDescriptor); + } + try { + List<HubEndpointInfo> endpointInfos = + mService.findEndpointsWithService(serviceDescriptor); + List<HubDiscoveryInfo> results = new ArrayList<>(endpointInfos.size()); + // Wrap with result type + for (HubEndpointInfo endpointInfo : endpointInfos) { + for (HubServiceInfo serviceInfo : endpointInfo.getServiceInfoCollection()) { + if (serviceInfo.getServiceDescriptor().equals(serviceDescriptor)) { + results.add(new HubDiscoveryInfo(endpointInfo, serviceInfo)); + } + } + } + return results; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Set a callback to receive messages from the context hub * * @param callback Callback object @@ -1010,6 +1075,80 @@ public final class ContextHubManager { } /** + * Registers an endpoint and its callback with the Context Hub Service. + * + * <p>An endpoint is registered with the Context Hub Service and published to the HAL. When the + * registration succeeds, the endpoint can receive notifications through the provided callback. + * + * @param hubEndpoint {@link HubEndpoint} object created by {@link HubEndpoint.Builder} + */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public void registerEndpoint(@NonNull HubEndpoint hubEndpoint) { + hubEndpoint.register(mService); + } + + /** + * Use a registered endpoint to connect to another endpoint (destination) without specifying a + * service. + * + * <p>Context Hub Service will create the endpoint session and notify the registered endpoint. + * The registered endpoint will receive callbacks on its {@link IHubEndpointLifecycleCallback} + * object regarding the lifecycle events of the session. + * + * @param hubEndpoint {@link HubEndpoint} object previously registered via {@link + * ContextHubManager#registerEndpoint(HubEndpoint)}. + * @param destination {@link HubEndpointInfo} object that represents an endpoint from previous + * endpoint discovery results (e.g. from {@link ContextHubManager#findEndpoints(long)}). + */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public void openSession( + @NonNull HubEndpoint hubEndpoint, @NonNull HubEndpointInfo destination) { + hubEndpoint.openSession(destination, null); + } + + /** + * Use a registered endpoint to connect to another endpoint (destination) for a service + * described by a {@link HubServiceInfo} object. + * + * <p>Context Hub Service will create the endpoint session and notify the registered endpoint. + * The registered endpoint will receive callbacks on its {@link IHubEndpointLifecycleCallback} + * object regarding the lifecycle events of the session. + * + * @param hubEndpoint {@link HubEndpoint} object previously registered via {@link + * ContextHubManager#registerEndpoint(HubEndpoint)}. + * @param destination {@link HubEndpointInfo} object that represents an endpoint from previous + * endpoint discovery results (e.g. from {@link ContextHubManager#findEndpoints(long)}). + * @param serviceInfo {@link HubServiceInfo} object that describes the service associated with + * this session. The information will be sent to the destination as part of open request. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public void openSession( + @NonNull HubEndpoint hubEndpoint, + @NonNull HubEndpointInfo destination, + @NonNull HubServiceInfo serviceInfo) { + hubEndpoint.openSession(destination, serviceInfo); + } + + /** + * Unregisters an endpoint and its callback with the Context Hub Service. + * + * <p>An endpoint is unregistered from the HAL. The endpoint object will no longer receive + * notification through the provided callback. + * + * @param hubEndpoint {@link HubEndpoint} object created by {@link HubEndpoint.Builder}. This + * should match a previously registered object via {@link + * ContextHubManager#registerEndpoint(HubEndpoint)}. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public void unregisterEndpoint(@NonNull HubEndpoint hubEndpoint) { + hubEndpoint.unregister(); + } + + /** * Queries for the list of preloaded nanoapp IDs on the system. * * @param hubInfo The Context Hub to query a list of nanoapp IDs from. @@ -1168,6 +1307,7 @@ public final class ContextHubManager { requireNonNull(mainLooper, "mainLooper cannot be null"); mService = service; mMainLooper = mainLooper; + try { mService.registerCallback(mClientCallback); } catch (RemoteException e) { diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java index bd87b5cb6d54..ee55f81bb2a7 100644 --- a/core/java/android/hardware/location/ContextHubTransaction.java +++ b/core/java/android/hardware/location/ContextHubTransaction.java @@ -51,18 +51,23 @@ public class ContextHubTransaction<T> { /** * Constants describing the type of a transaction through the Context Hub Service. - * {@hide} + * + * @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "TYPE_" }, value = { - TYPE_LOAD_NANOAPP, - TYPE_UNLOAD_NANOAPP, - TYPE_ENABLE_NANOAPP, - TYPE_DISABLE_NANOAPP, - TYPE_QUERY_NANOAPPS, - TYPE_RELIABLE_MESSAGE, - }) - public @interface Type { } + @IntDef( + prefix = {"TYPE_"}, + value = { + TYPE_LOAD_NANOAPP, + TYPE_UNLOAD_NANOAPP, + TYPE_ENABLE_NANOAPP, + TYPE_DISABLE_NANOAPP, + TYPE_QUERY_NANOAPPS, + TYPE_RELIABLE_MESSAGE, + TYPE_HUB_MESSAGE_DEFAULT, + TYPE_HUB_MESSAGE_REQUIRES_RESPONSE, + }) + public @interface Type {} public static final int TYPE_LOAD_NANOAPP = 0; public static final int TYPE_UNLOAD_NANOAPP = 1; @@ -71,24 +76,34 @@ public class ContextHubTransaction<T> { public static final int TYPE_QUERY_NANOAPPS = 4; public static final int TYPE_RELIABLE_MESSAGE = 5; + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public static final int TYPE_HUB_MESSAGE_DEFAULT = 6; + + @FlaggedApi(Flags.FLAG_OFFLOAD_API) + public static final int TYPE_HUB_MESSAGE_REQUIRES_RESPONSE = 7; + /** * Constants describing the result of a transaction or request through the Context Hub Service. - * {@hide} + * + * @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "RESULT_" }, value = { - RESULT_SUCCESS, - RESULT_FAILED_UNKNOWN, - RESULT_FAILED_BAD_PARAMS, - RESULT_FAILED_UNINITIALIZED, - RESULT_FAILED_BUSY, - RESULT_FAILED_AT_HUB, - RESULT_FAILED_TIMEOUT, - RESULT_FAILED_SERVICE_INTERNAL_FAILURE, - RESULT_FAILED_HAL_UNAVAILABLE, - RESULT_FAILED_NOT_SUPPORTED, - }) + @IntDef( + prefix = {"RESULT_"}, + value = { + RESULT_SUCCESS, + RESULT_FAILED_UNKNOWN, + RESULT_FAILED_BAD_PARAMS, + RESULT_FAILED_UNINITIALIZED, + RESULT_FAILED_BUSY, + RESULT_FAILED_AT_HUB, + RESULT_FAILED_TIMEOUT, + RESULT_FAILED_SERVICE_INTERNAL_FAILURE, + RESULT_FAILED_HAL_UNAVAILABLE, + RESULT_FAILED_NOT_SUPPORTED, + }) public @interface Result {} + public static final int RESULT_SUCCESS = 0; /** * Generic failure mode. @@ -143,7 +158,8 @@ public class ContextHubTransaction<T> { */ private R mContents; - Response(@ContextHubTransaction.Result int result, R contents) { + /** @hide */ + public Response(@ContextHubTransaction.Result int result, R contents) { mResult = result; mContents = contents; } @@ -206,7 +222,8 @@ public class ContextHubTransaction<T> { */ private boolean mIsResponseSet = false; - ContextHubTransaction(@Type int type) { + /** @hide */ + public ContextHubTransaction(@Type int type) { mTransactionType = type; } @@ -338,16 +355,16 @@ public class ContextHubTransaction<T> { /** * Sets the response of the transaction. * - * This method should only be invoked by ContextHubManager as a result of a callback from - * the Context Hub Service indicating the response from a transaction. This method should not be + * <p>This method should only be invoked by ContextHubManager as a result of a callback from the + * Context Hub Service indicating the response from a transaction. This method should not be * invoked more than once. * * @param response the response to set - * * @throws IllegalStateException if this method is invoked multiple times * @throws NullPointerException if the response is null + * @hide */ - /* package */ void setResponse(ContextHubTransaction.Response<T> response) { + public void setResponse(ContextHubTransaction.Response<T> response) { synchronized (this) { Objects.requireNonNull(response, "Response cannot be null"); if (mIsResponseSet) { diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl index b0cc763dc8fd..f9f412446038 100644 --- a/core/java/android/hardware/location/IContextHubService.aidl +++ b/core/java/android/hardware/location/IContextHubService.aidl @@ -18,17 +18,20 @@ package android.hardware.location; // Declare any non-default types here with import statements import android.app.PendingIntent; -import android.hardware.location.HubInfo; +import android.hardware.contexthub.HubEndpointInfo; +import android.hardware.contexthub.IContextHubEndpoint; +import android.hardware.contexthub.IContextHubEndpointCallback; import android.hardware.location.ContextHubInfo; import android.hardware.location.ContextHubMessage; -import android.hardware.location.NanoApp; -import android.hardware.location.NanoAppBinary; -import android.hardware.location.NanoAppFilter; -import android.hardware.location.NanoAppInstanceInfo; +import android.hardware.location.HubInfo; import android.hardware.location.IContextHubCallback; import android.hardware.location.IContextHubClient; import android.hardware.location.IContextHubClientCallback; import android.hardware.location.IContextHubTransactionCallback; +import android.hardware.location.NanoApp; +import android.hardware.location.NanoAppBinary; +import android.hardware.location.NanoAppFilter; +import android.hardware.location.NanoAppInstanceInfo; /** * @hide @@ -122,4 +125,16 @@ interface IContextHubService { // Enables or disables test mode @EnforcePermission("ACCESS_CONTEXT_HUB") boolean setTestMode(in boolean enable); + + // Finds all endpoints that has a specific ID + @EnforcePermission("ACCESS_CONTEXT_HUB") + List<HubEndpointInfo> findEndpoints(long endpointId); + + // Finds all endpoints that has a specific service + @EnforcePermission("ACCESS_CONTEXT_HUB") + List<HubEndpointInfo> findEndpointsWithService(String service); + + // Register an endpoint with the context hub + @EnforcePermission("ACCESS_CONTEXT_HUB") + IContextHubEndpoint registerEndpoint(in HubEndpointInfo pendingEndpointInfo, in IContextHubEndpointCallback callback); } diff --git a/core/java/android/net/vcn/VcnFrameworkInitializer.java b/core/java/android/net/ConnectivityFrameworkInitializerBaklava.java index 8cb213b306be..1f0fa92d7976 100644 --- a/core/java/android/net/vcn/VcnFrameworkInitializer.java +++ b/core/java/android/net/ConnectivityFrameworkInitializerBaklava.java @@ -14,15 +14,21 @@ * limitations under the License. */ -package android.net.vcn; +package android.net; +import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; + +import android.annotation.FlaggedApi; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.app.SystemServiceRegistry; import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.Context; import android.content.pm.PackageManager; +import android.net.vcn.IVcnManagementService; +import android.net.vcn.VcnManager; import android.os.Build; import android.os.SystemProperties; @@ -31,8 +37,9 @@ import android.os.SystemProperties; * * @hide */ -// TODO: Expose it as @SystemApi(client = MODULE_LIBRARIES) -public final class VcnFrameworkInitializer { +@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class ConnectivityFrameworkInitializerBaklava { /** * Starting with {@link VANILLA_ICE_CREAM}, Telephony feature flags (e.g. {@link * PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}) are being checked before returning managers @@ -55,7 +62,7 @@ public final class VcnFrameworkInitializer { */ private static final int VENDOR_API_FOR_ANDROID_V = 202404; - private VcnFrameworkInitializer() {} + private ConnectivityFrameworkInitializerBaklava() {} // Suppressing AndroidFrameworkCompatChange because we're querying vendor // partition SDK level, not application's target SDK version (which BTW we @@ -86,7 +93,10 @@ public final class VcnFrameworkInitializer { * * @throws IllegalStateException if this is called anywhere besides {@link * SystemServiceRegistry}. + * @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static void registerServiceWrappers() { SystemServiceRegistry.registerContextAwareService( VcnManager.VCN_MANAGEMENT_SERVICE_STRING, diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java index af93c964a8ba..3219ce81c256 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -16,6 +16,7 @@ package android.net.vcn; import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE; +import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; import static android.net.vcn.Flags.FLAG_SAFE_MODE_CONFIG; import static android.net.vcn.VcnUnderlyingNetworkTemplate.MATCH_REQUIRED; @@ -82,7 +83,15 @@ import java.util.concurrent.TimeUnit; * </ul> */ public final class VcnGatewayConnectionConfig { - /** @hide */ + /** + * Minimum NAT timeout not set. + * + * <p>When the timeout is not set, the device will automatically choose a keepalive interval and + * may reduce the keepalive frequency for power-optimization. + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + // This constant does not represent a minimum value. It indicates the value is not configured. + @SuppressLint("MinMaxConstant") public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET = -1; /** @hide */ @@ -773,7 +782,7 @@ public final class VcnGatewayConnectionConfig { * * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN - * Gateway. + * Gateway; or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} to clear this value. * @return this {@link Builder} instance, for chaining */ @NonNull @@ -781,8 +790,10 @@ public final class VcnGatewayConnectionConfig { @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { Preconditions.checkArgument( - minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, - "Timeout must be at least 120s"); + minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || minUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return this; diff --git a/core/java/android/net/vcn/VcnTransportInfo.java b/core/java/android/net/vcn/VcnTransportInfo.java index 1fc91eea3138..3638429f33fb 100644 --- a/core/java/android/net/vcn/VcnTransportInfo.java +++ b/core/java/android/net/vcn/VcnTransportInfo.java @@ -17,13 +17,16 @@ package android.net.vcn; import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS; +import static android.net.vcn.Flags.FLAG_MAINLINE_VCN_MODULE_API; import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS; import static android.net.vcn.VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; +import android.annotation.FlaggedApi; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.net.NetworkCapabilities; import android.net.TransportInfo; import android.net.wifi.WifiInfo; @@ -52,23 +55,29 @@ import java.util.Objects; * @hide */ // TODO: Do not store WifiInfo and subscription ID in VcnTransportInfo anymore -public class VcnTransportInfo implements TransportInfo, Parcelable { +@FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class VcnTransportInfo implements TransportInfo, Parcelable { @Nullable private final WifiInfo mWifiInfo; private final int mSubId; private final int mMinUdpPort4500NatTimeoutSeconds; + /** @hide */ public VcnTransportInfo(@NonNull WifiInfo wifiInfo) { this(wifiInfo, INVALID_SUBSCRIPTION_ID, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); } + /** @hide */ public VcnTransportInfo(@NonNull WifiInfo wifiInfo, int minUdpPort4500NatTimeoutSeconds) { this(wifiInfo, INVALID_SUBSCRIPTION_ID, minUdpPort4500NatTimeoutSeconds); } + /** @hide */ public VcnTransportInfo(int subId) { this(null /* wifiInfo */, subId, MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET); } + /** @hide */ public VcnTransportInfo(int subId, int minUdpPort4500NatTimeoutSeconds) { this(null /* wifiInfo */, subId, minUdpPort4500NatTimeoutSeconds); } @@ -86,6 +95,7 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { * <p>If the underlying Network for the associated VCN is Cellular, returns null. * * @return the WifiInfo if there is an underlying WiFi connection, else null. + * @hide */ @Nullable public WifiInfo getWifiInfo() { @@ -100,17 +110,27 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { * * @return the Subscription ID if a cellular underlying Network is present, else {@link * android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}. + * @hide */ public int getSubId() { return mSubId; } /** - * Get the VCN provided UDP port 4500 NAT timeout + * Get the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping. * - * @return the UDP 4500 NAT timeout, or + * <p>To ensure uninterrupted connectivity, the device must send keepalive packets before the + * timeout. Failure to do so may result in the mapping being cleared and connection termination. + * This value is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, + * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. + * + * @return the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping, or * VcnGatewayConnectionConfig.MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET if not set. + * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int) + * @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public int getMinUdpPort4500NatTimeoutSeconds() { return mMinUdpPort4500NatTimeoutSeconds; } @@ -129,12 +149,21 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { && mMinUdpPort4500NatTimeoutSeconds == that.mMinUdpPort4500NatTimeoutSeconds; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public int describeContents() { return 0; } + /** @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override @NonNull public TransportInfo makeCopy(long redactions) { @@ -149,6 +178,9 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { mMinUdpPort4500NatTimeoutSeconds); } + /** @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public long getApplicableRedactions() { long redactions = REDACT_FOR_NETWORK_SETTINGS; @@ -161,7 +193,13 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return redactions; } - /** {@inheritDoc} */ + /** + * {@inheritDoc} + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mSubId); @@ -174,7 +212,13 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { return "VcnTransportInfo { mWifiInfo = " + mWifiInfo + ", mSubId = " + mSubId + " }"; } - /** Implement the Parcelable interface */ + /** + * Implement the Parcelable interface + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final @NonNull Creator<VcnTransportInfo> CREATOR = new Creator<VcnTransportInfo>() { public VcnTransportInfo createFromParcel(Parcel in) { @@ -201,37 +245,63 @@ public class VcnTransportInfo implements TransportInfo, Parcelable { } }; - /** This class can be used to construct a {@link VcnTransportInfo}. */ + /** + * This class can be used to construct a {@link VcnTransportInfo}. + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final class Builder { private int mMinUdpPort4500NatTimeoutSeconds = MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET; - /** Construct Builder */ + /** + * Construct Builder + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public Builder() {} /** - * Sets the maximum supported IKEv2/IPsec NATT keepalive timeout. + * Set the minimum duration that the VCN Gateway guarantees to preserve a NAT mapping. * * <p>This is used as a power-optimization hint for other IKEv2/IPsec use cases (e.g. VPNs, * or IWLAN) to reduce the necessary keepalive frequency, thus conserving power and data. * - * @param minUdpPort4500NatTimeoutSeconds the maximum keepalive timeout supported by the VCN - * Gateway Connection, generally the minimum duration a NAT mapping is cached on the VCN - * Gateway. + * @param minUdpPort4500NatTimeoutSeconds the minimum duration that the VCN Gateway + * guarantees to preserve a NAT mapping, or {@link MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET} + * to clear this value. To ensure uninterrupted connectivity, the device must send + * keepalive packets within this interval. Failure to do so may result in the mapping + * being cleared and connection termination. * @return this {@link Builder} instance, for chaining + * @see VcnGatewayConnectionConfig.Builder#setMinUdpPort4500NatTimeoutSeconds(int) + * @hide */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public Builder setMinUdpPort4500NatTimeoutSeconds( @IntRange(from = MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS) int minUdpPort4500NatTimeoutSeconds) { Preconditions.checkArgument( - minUdpPort4500NatTimeoutSeconds >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, - "Timeout must be at least 120s"); + minUdpPort4500NatTimeoutSeconds == MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET + || minUdpPort4500NatTimeoutSeconds + >= MIN_UDP_PORT_4500_NAT_TIMEOUT_SECONDS, + "Timeout must be at least 120s or MIN_UDP_PORT_4500_NAT_TIMEOUT_UNSET"); mMinUdpPort4500NatTimeoutSeconds = minUdpPort4500NatTimeoutSeconds; return Builder.this; } - /** Build a VcnTransportInfo instance */ + /** + * Build a VcnTransportInfo instance + * + * @hide + */ + @FlaggedApi(FLAG_MAINLINE_VCN_MODULE_API) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public VcnTransportInfo build() { return new VcnTransportInfo( diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java index 99e7d166446e..05bd10b053fe 100644 --- a/core/java/android/os/Bundle.java +++ b/core/java/android/os/Bundle.java @@ -18,10 +18,12 @@ package android.os; import static java.util.Objects.requireNonNull; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.util.ArrayMap; import android.util.Size; @@ -72,16 +74,18 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { /** * Status when the Bundle can <b>assert</b> that the underlying Parcel DOES NOT contain * Binder object(s). - * * @hide */ + @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final int STATUS_BINDERS_NOT_PRESENT = 0; /** * Status when the Bundle can <b>assert</b> that there are Binder object(s) in the Parcel. - * * @hide */ + @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final int STATUS_BINDERS_PRESENT = 1; /** @@ -94,9 +98,10 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * object to the Bundle but it is not possible to assert this fact unless the Bundle is written * to a Parcel. * </p> - * * @hide */ + @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final int STATUS_BINDERS_UNKNOWN = 2; /** @hide */ @@ -417,6 +422,8 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable { * Returns a status indicating whether the bundle contains any parcelled Binder objects. * @hide */ + @FlaggedApi(Flags.FLAG_ENABLE_HAS_BINDERS) + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public @HasBinderStatus int hasBinders() { if ((mFlags & FLAG_HAS_BINDERS_KNOWN) != 0) { if ((mFlags & FLAG_HAS_BINDERS) != 0) { diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java index 7529ab9ab894..036ccd84a600 100644 --- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java +++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java @@ -19,6 +19,8 @@ package android.os; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.TestApi; +import android.app.ActivityThread; +import android.app.Instrumentation; import android.compat.annotation.UnsupportedAppUsage; import android.os.Process; import android.os.UserHandle; @@ -31,7 +33,6 @@ import android.util.SparseArray; import android.util.proto.ProtoOutputStream; import dalvik.annotation.optimization.NeverCompile; -import dalvik.system.VMDebug; import java.io.FileDescriptor; import java.lang.annotation.Retention; @@ -111,11 +112,39 @@ public final class MessageQueue { private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events); MessageQueue(boolean quitAllowed) { - mUseConcurrent = UserHandle.isCore(Process.myUid()) && !VMDebug.isDebuggingEnabled(); + // Concurrent mode modifies behavior that is observable via reflection and is commonly used + // by tests. + // For now, we limit it to system processes to avoid breaking apps and their tests. + mUseConcurrent = UserHandle.isCore(Process.myUid()); + // Even then, we don't use it if instrumentation is loaded as it breaks some + // platform tests. + final Instrumentation instrumentation = getInstrumentation(); + mUseConcurrent &= instrumentation == null || !instrumentation.isInstrumenting(); + // We can lift this restriction in the future after we've made it possible for test authors + // to test Looper and MessageQueue without resorting to reflection. + + // Holdback study. + if (mUseConcurrent && Flags.messageQueueForceLegacy()) { + mUseConcurrent = false; + } + mQuitAllowed = quitAllowed; mPtr = nativeInit(); } + @android.ravenwood.annotation.RavenwoodReplace(blockedBy = ActivityThread.class) + private static Instrumentation getInstrumentation() { + final ActivityThread activityThread = ActivityThread.currentActivityThread(); + if (activityThread != null) { + return activityThread.getInstrumentation(); + } + return null; + } + + private static Instrumentation getInstrumentation$ravenwood() { + return null; // Instrumentation not supported on Ravenwood yet. + } + @Override protected void finalize() throws Throwable { try { diff --git a/core/java/android/os/CpuHeadroomParams.java b/core/java/android/os/CpuHeadroomParams.java new file mode 100644 index 000000000000..f0d4f7d8737f --- /dev/null +++ b/core/java/android/os/CpuHeadroomParams.java @@ -0,0 +1,91 @@ +/* + * 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 android.os; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.os.health.SystemHealthManager; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Headroom request params used by {@link SystemHealthManager#getCpuHeadroom(CpuHeadroomParams)}. + */ +@FlaggedApi(Flags.FLAG_CPU_GPU_HEADROOMS) +public final class CpuHeadroomParams { + final CpuHeadroomParamsInternal mInternal; + + public CpuHeadroomParams() { + mInternal = new CpuHeadroomParamsInternal(); + } + + /** @hide */ + @IntDef(flag = false, prefix = {"CPU_HEADROOM_CALCULATION_TYPE_"}, value = { + CPU_HEADROOM_CALCULATION_TYPE_MIN, // 0 + CPU_HEADROOM_CALCULATION_TYPE_AVERAGE, // 1 + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CpuHeadroomCalculationType { + } + + /** + * Calculates the headroom based on minimum value over a device-defined window. + */ + public static final int CPU_HEADROOM_CALCULATION_TYPE_MIN = 0; + + /** + * Calculates the headroom based on average value over a device-defined window. + */ + public static final int CPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; + + /** + * Sets the headroom calculation type. + * <p> + * + * @throws IllegalArgumentException if the type is invalid. + */ + public void setCalculationType(@CpuHeadroomCalculationType int calculationType) { + switch (calculationType) { + case CPU_HEADROOM_CALCULATION_TYPE_MIN: + case CPU_HEADROOM_CALCULATION_TYPE_AVERAGE: + mInternal.calculationType = (byte) calculationType; + return; + } + throw new IllegalArgumentException("Invalid calculation type: " + calculationType); + } + + /** + * Gets the headroom calculation type. + * Default to {@link #CPU_HEADROOM_CALCULATION_TYPE_MIN} if not set. + */ + public @CpuHeadroomCalculationType int getCalculationType() { + @CpuHeadroomCalculationType int validatedType = switch ((int) mInternal.calculationType) { + case CPU_HEADROOM_CALCULATION_TYPE_MIN, CPU_HEADROOM_CALCULATION_TYPE_AVERAGE -> + mInternal.calculationType; + default -> CPU_HEADROOM_CALCULATION_TYPE_MIN; + }; + return validatedType; + } + + /** + * @hide + */ + public CpuHeadroomParamsInternal getInternal() { + return mInternal; + } +} diff --git a/core/java/android/os/CpuHeadroomParamsInternal.aidl b/core/java/android/os/CpuHeadroomParamsInternal.aidl new file mode 100644 index 000000000000..6cc4699a809e --- /dev/null +++ b/core/java/android/os/CpuHeadroomParamsInternal.aidl @@ -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 android.os; + +import android.hardware.power.CpuHeadroomParams; + +/** + * Changes should be synced with match function of HintManagerService#CpuHeadroomCacheItem. + * {@hide} + */ +@JavaDerive(equals = true, toString = true) +parcelable CpuHeadroomParamsInternal { + boolean usesDeviceHeadroom = false; + CpuHeadroomParams.CalculationType calculationType = CpuHeadroomParams.CalculationType.MIN; + CpuHeadroomParams.SelectionType selectionType = CpuHeadroomParams.SelectionType.ALL; +} + diff --git a/core/java/android/os/GpuHeadroomParams.java b/core/java/android/os/GpuHeadroomParams.java new file mode 100644 index 000000000000..efb2a28ad2b5 --- /dev/null +++ b/core/java/android/os/GpuHeadroomParams.java @@ -0,0 +1,91 @@ +/* + * 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 android.os; + +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.os.health.SystemHealthManager; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Headroom request params used by {@link SystemHealthManager#getGpuHeadroom(GpuHeadroomParams)}. + */ +@FlaggedApi(Flags.FLAG_CPU_GPU_HEADROOMS) +public final class GpuHeadroomParams { + final GpuHeadroomParamsInternal mInternal; + + public GpuHeadroomParams() { + mInternal = new GpuHeadroomParamsInternal(); + } + + /** @hide */ + @IntDef(flag = false, prefix = {"GPU_HEADROOM_CALCULATION_TYPE_"}, value = { + GPU_HEADROOM_CALCULATION_TYPE_MIN, // 0 + GPU_HEADROOM_CALCULATION_TYPE_AVERAGE, // 1 + }) + @Retention(RetentionPolicy.SOURCE) + public @interface GpuHeadroomCalculationType { + } + + /** + * Calculates the headroom based on minimum value over a device-defined window. + */ + public static final int GPU_HEADROOM_CALCULATION_TYPE_MIN = 0; + + /** + * Calculates the headroom based on average value over a device-defined window. + */ + public static final int GPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1; + + /** + * Sets the headroom calculation type. + * <p> + * + * @throws IllegalArgumentException if the type is invalid. + */ + public void setCalculationType(@GpuHeadroomCalculationType int calculationType) { + switch (calculationType) { + case GPU_HEADROOM_CALCULATION_TYPE_MIN: + case GPU_HEADROOM_CALCULATION_TYPE_AVERAGE: + mInternal.calculationType = (byte) calculationType; + return; + } + throw new IllegalArgumentException("Invalid calculation type: " + calculationType); + } + + /** + * Gets the headroom calculation type. + * Default to {@link #GPU_HEADROOM_CALCULATION_TYPE_MIN} if not set. + */ + public @GpuHeadroomCalculationType int getCalculationType() { + @GpuHeadroomCalculationType int validatedType = switch ((int) mInternal.calculationType) { + case GPU_HEADROOM_CALCULATION_TYPE_MIN, GPU_HEADROOM_CALCULATION_TYPE_AVERAGE -> + mInternal.calculationType; + default -> GPU_HEADROOM_CALCULATION_TYPE_MIN; + }; + return validatedType; + } + + /** + * @hide + */ + public GpuHeadroomParamsInternal getInternal() { + return mInternal; + } +} diff --git a/core/java/android/os/GpuHeadroomParamsInternal.aidl b/core/java/android/os/GpuHeadroomParamsInternal.aidl new file mode 100644 index 000000000000..20309e7673f2 --- /dev/null +++ b/core/java/android/os/GpuHeadroomParamsInternal.aidl @@ -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 android.os; + +import android.hardware.power.GpuHeadroomParams; + +/** + * Changes should be synced with match function of HintManagerService#GpuHeadroomCacheItem. + * {@hide} + */ +@JavaDerive(equals = true, toString = true) +parcelable GpuHeadroomParamsInternal { + GpuHeadroomParams.CalculationType calculationType = GpuHeadroomParams.CalculationType.MIN; +} diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl index 73cdd5682f31..33120556339f 100644 --- a/core/java/android/os/IHintManager.aidl +++ b/core/java/android/os/IHintManager.aidl @@ -17,6 +17,8 @@ package android.os; +import android.os.CpuHeadroomParamsInternal; +import android.os.GpuHeadroomParamsInternal; import android.os.IHintSession; import android.hardware.power.ChannelConfig; import android.hardware.power.SessionConfig; @@ -50,4 +52,8 @@ interface IHintManager { */ @nullable ChannelConfig getSessionChannel(in IBinder token); oneway void closeSessionChannel(); + float[] getCpuHeadroom(in CpuHeadroomParamsInternal params); + long getCpuHeadroomMinIntervalMillis(); + float getGpuHeadroom(in GpuHeadroomParamsInternal params); + long getGpuHeadroomMinIntervalMillis(); } diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS index 590ddb404b63..e63b6648a9ef 100644 --- a/core/java/android/os/OWNERS +++ b/core/java/android/os/OWNERS @@ -78,6 +78,9 @@ per-file PatternMatcher* = file:/PACKAGE_MANAGER_OWNERS # PermissionEnforcer per-file PermissionEnforcer.java = tweek@google.com, brufino@google.com +# RemoteCallbackList +per-file RemoteCallbackList.java = shayba@google.com + # ART per-file ArtModuleServiceManager.java = file:platform/art:/OWNERS @@ -125,3 +128,6 @@ per-file StatsServiceManager.java = file:/services/core/java/com/android/server/ # Dropbox per-file DropBoxManager* = mwachens@google.com + +# Flags +per-file flags.aconfig = file:/FF_LEADS_OWNERS diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 9ab92285c167..5a53bc1552b8 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -5308,7 +5308,13 @@ public class UserManager { Manifest.permission.MANAGE_USERS, Manifest.permission.CREATE_USERS, Manifest.permission.QUERY_USERS}, conditional = true) + @CachedProperty(api = "user_manager_user_data") public List<UserInfo> getProfiles(@UserIdInt int userId) { + if (android.multiuser.Flags.cacheProfilesReadOnly()) { + return UserManagerCache.getProfiles( + (Integer userIdentifier) -> mService.getProfiles(userIdentifier, false), + userId); + } try { return mService.getProfiles(userId, false /* enabledOnly */); } catch (RemoteException re) { @@ -6484,6 +6490,19 @@ public class UserManager { } /** + * This method is used to invalidate caches, when UserManagerService.mUsers + * {@link UserManagerService.UserData} is modified, including changes to {@link UserInfo}. + * In practice we determine modification by when that data is persisted, or scheduled to be + * presisted, to xml. + * @hide + */ + public static final void invalidateCacheOnUserDataChanged() { + if (android.multiuser.Flags.cacheProfilesReadOnly()) { + UserManagerCache.invalidateProfiles(); + } + } + + /** * Returns a serial number on this device for a given userId. User handles can be recycled * when deleting and creating users, but serial numbers are not reused until the device is * wiped. diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index 70cbc732366a..f6bc3894be4b 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -1826,52 +1826,6 @@ public abstract class VibrationEffect implements Parcelable { } /** - * Start building a waveform vibration. - * - * <p>The waveform envelope builder offers more flexibility for creating waveform effects, - * allowing control over vibration amplitude and frequency via smooth transitions between - * values. The waveform will start the first transition from the vibrator off state, using - * the same frequency of the first control point. To provide a different initial vibration - * frequency, use {@link #startWaveformEnvelope(float)}. - * - * <p>Note: To check whether waveform envelope effects are supported, use - * {@link Vibrator#areEnvelopeEffectsSupported()}. - * - * @see VibrationEffect.WaveformEnvelopeBuilder - */ - @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) - @NonNull - public static VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope() { - return new WaveformEnvelopeBuilder(); - } - - /** - * Start building a waveform vibration with an initial frequency. - * - * <p>The waveform envelope builder offers more flexibility for creating waveform effects, - * allowing control over vibration amplitude and frequency via smooth transitions between - * values. - * - * <p>This is the same as {@link #startWaveformEnvelope()}, but the waveform will start - * vibrating at given frequency, in hertz, while it transitions to the new amplitude and - * frequency of the first control point. - * - * <p>Note: To check whether waveform envelope effects are supported, use - * {@link Vibrator#areEnvelopeEffectsSupported()}. - * - * @param initialFrequencyHz The starting frequency of the vibration, in hertz. Must be greater - * than zero. - * - * @see VibrationEffect.WaveformEnvelopeBuilder - */ - @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) - @NonNull - public static VibrationEffect.WaveformEnvelopeBuilder startWaveformEnvelope( - @FloatRange(from = 0) float initialFrequencyHz) { - return new WaveformEnvelopeBuilder(initialFrequencyHz); - } - - /** * A builder for waveform effects described by its envelope. * * <p>Waveform effect envelopes are defined by one or more control points describing a target @@ -1882,7 +1836,7 @@ public abstract class VibrationEffect implements Parcelable { * 100ms, holds that state for 200ms, and then ramps back down over 100ms: * * <pre>{@code - * VibrationEffect effect = VibrationEffect.startWaveformEnvelope() + * VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder() * .addControlPoint(1.0f, 120f, 100) * .addControlPoint(1.0f, 120f, 200) * .addControlPoint(0.0f, 120f, 100) @@ -1916,20 +1870,48 @@ public abstract class VibrationEffect implements Parcelable { * {@link VibratorEnvelopeEffectInfo#getMaxControlPointDurationMillis()} * <li>Maximum total effect duration: {@link VibratorEnvelopeEffectInfo#getMaxDurationMillis()} * </ul> - * - * @see VibrationEffect#startWaveformEnvelope() */ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) public static final class WaveformEnvelopeBuilder { private ArrayList<PwleSegment> mSegments = new ArrayList<>(); private float mLastAmplitude = 0f; - private float mLastFrequencyHz = 0f; + private float mLastFrequencyHz = Float.NaN; + + public WaveformEnvelopeBuilder() {} + + /** + * Sets the initial frequency for the waveform in Hertz. + * + * <p>The effect will start vibrating at this frequency when it transitions to the + * amplitude and frequency defined by the first control point. + * + * <p>The frequency must be greater than zero and within the supported range. To determine + * the supported range, use {@link Vibrator#getFrequencyProfile()}. Creating + * effects using frequencies outside this range will result in the vibration not playing. + * + * @param initialFrequencyHz The starting frequency of the vibration, in Hz. Must be + * greater than zero. + */ + @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) + @SuppressWarnings("MissingGetterMatchingBuilder")// No getter to initial frequency once set. + @NonNull + public WaveformEnvelopeBuilder setInitialFrequencyHz( + @FloatRange(from = 0) float initialFrequencyHz) { - private WaveformEnvelopeBuilder() {} + if (mSegments.isEmpty()) { + mLastFrequencyHz = initialFrequencyHz; + } else { + PwleSegment firstSegment = mSegments.getFirst(); + mSegments.set(0, new PwleSegment( + firstSegment.getStartAmplitude(), + firstSegment.getEndAmplitude(), + initialFrequencyHz, // Update start frequency + firstSegment.getEndFrequencyHz(), + (int) firstSegment.getDuration())); + } - private WaveformEnvelopeBuilder(float initialFrequency) { - mLastFrequencyHz = initialFrequency; + return this; } /** @@ -1940,15 +1922,13 @@ public abstract class VibrationEffect implements Parcelable { * perceived intensity. It's determined by the actuator response curve. * * <p>Frequency must be greater than zero and within the supported range. To determine - * the supported range, use {@link Vibrator#getFrequencyProfile()}. This method returns a - * {@link android.os.vibrator.VibratorFrequencyProfile} object, which contains the - * minimum and maximum frequencies, among other frequency-related information. Creating + * the supported range, use {@link Vibrator#getFrequencyProfile()}. Creating * effects using frequencies outside this range will result in the vibration not playing. * * <p>Time specifies the duration (in milliseconds) for the vibrator to smoothly transition * from the previous control point to this new one. It must be greater than zero. To * transition as quickly as possible, use - * {@link Vibrator#getMinEnvelopeEffectControlPointDurationMillis()}. + * {@link VibratorEnvelopeEffectInfo#getMinControlPointDurationMillis()}. * * @param amplitude The amplitude value between 0 and 1, inclusive. 0 represents the * vibrator being off, and 1 represents the maximum achievable amplitude @@ -1963,7 +1943,7 @@ public abstract class VibrationEffect implements Parcelable { @FloatRange(from = 0, to = 1) float amplitude, @FloatRange(from = 0) float frequencyHz, int timeMillis) { - if (mLastFrequencyHz == 0) { + if (Float.isNaN(mLastFrequencyHz)) { mLastFrequencyHz = frequencyHz; } @@ -1984,6 +1964,7 @@ public abstract class VibrationEffect implements Parcelable { * calling this method again. * * @return The {@link VibrationEffect} resulting from the list of control points. + * @throws IllegalStateException if no control points were added to the builder. */ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) @NonNull diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig index d9db28e0b3c3..9b1bf057b815 100644 --- a/core/java/android/os/flags.aconfig +++ b/core/java/android/os/flags.aconfig @@ -4,6 +4,15 @@ container: "system" # keep-sorted start block=yes newline_separated=yes flag { + # Holdback study for concurrent MessageQueue. + # Do not promote beyond trunkfood. + namespace: "system_performance" + name: "message_queue_force_legacy" + description: "Whether to holdback concurrent MessageQueue (force legacy)." + bug: "336880969" +} + +flag { name: "adpf_gpu_report_actual_work_duration" is_exported: true namespace: "game" @@ -66,6 +75,14 @@ flag { } flag { + name: "adpf_use_load_hints" + namespace: "game" + description: "Guards use of the ADPF public load hints behind a readonly flag" + is_fixed_read_only: true + bug: "367803904" +} + +flag { name: "allow_consentless_bugreport_delegated_consent" namespace: "crumpet" description: "Allow privileged apps to call bugreport generation without enforcing user consent and delegate it to the calling app instead" @@ -148,6 +165,13 @@ flag { } flag { + name: "cpu_gpu_headrooms" + namespace: "game" + description: "Feature flag for adding CPU/GPU headroom API" + bug: "346604998" +} + +flag { name: "disallow_cellular_null_ciphers_restriction" namespace: "cellular_security" description: "Guards a new UserManager user restriction that admins can use to require cellular encryption on their managed devices." @@ -179,6 +203,17 @@ flag { } flag { + name: "material_colors_10_2024" + namespace: "systemui" + description: "Adding new Material Tokens as of October 2024" + bug: "376195115" + is_exported: true + metadata { + purpose: PURPOSE_FEATURE + } +} + +flag { name: "message_queue_tail_tracking" namespace: "system_performance" description: "track tail of message queue." @@ -253,6 +288,15 @@ flag { flag { namespace: "system_performance" + name: "enable_has_binders" + is_exported: true + description: "Add hasBinders to Public API under a flag." + is_fixed_read_only: true + bug: "330345513" +} + +flag { + namespace: "system_performance" name: "perfetto_sdk_tracing" description: "Tracing using Perfetto SDK." bug: "303199244" diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java index deabfed365a6..4db9bc333e2b 100644 --- a/core/java/android/os/health/SystemHealthManager.java +++ b/core/java/android/os/health/SystemHealthManager.java @@ -17,6 +17,7 @@ package android.os.health; import android.annotation.FlaggedApi; +import android.annotation.FloatRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemService; @@ -25,6 +26,11 @@ import android.content.Context; import android.os.BatteryStats; import android.os.Build; import android.os.Bundle; +import android.os.CpuHeadroomParams; +import android.os.CpuHeadroomParamsInternal; +import android.os.GpuHeadroomParams; +import android.os.GpuHeadroomParamsInternal; +import android.os.IHintManager; import android.os.IPowerStatsService; import android.os.OutcomeReceiver; import android.os.PowerMonitor; @@ -68,6 +74,8 @@ public class SystemHealthManager { private final IBatteryStats mBatteryStats; @Nullable private final IPowerStatsService mPowerStats; + @Nullable + private final IHintManager mHintManager; private List<PowerMonitor> mPowerMonitorsInfo; private final Object mPowerMonitorsLock = new Object(); private static final long TAKE_UID_SNAPSHOT_TIMEOUT_MILLIS = 10_000; @@ -88,14 +96,111 @@ public class SystemHealthManager { public SystemHealthManager() { this(IBatteryStats.Stub.asInterface(ServiceManager.getService(BatteryStats.SERVICE_NAME)), IPowerStatsService.Stub.asInterface( - ServiceManager.getService(Context.POWER_STATS_SERVICE))); + ServiceManager.getService(Context.POWER_STATS_SERVICE)), + IHintManager.Stub.asInterface( + ServiceManager.getService(Context.PERFORMANCE_HINT_SERVICE))); } /** {@hide} */ public SystemHealthManager(@NonNull IBatteryStats batteryStats, - @Nullable IPowerStatsService powerStats) { + @Nullable IPowerStatsService powerStats, @Nullable IHintManager hintManager) { mBatteryStats = batteryStats; mPowerStats = powerStats; + mHintManager = hintManager; + } + + /** + * Provides an estimate of global available CPU headroom of the calling thread. + * <p> + * + * @param params params to customize the CPU headroom calculation, null to use default params. + * @return a single value a {@code Float.NaN} if it's temporarily unavailable. + * A valid value is ranged from [0, 100], where 0 indicates no more CPU resources can be + * granted. + * @throws UnsupportedOperationException if the API is unsupported or the request params can't + * be served. + */ + @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS) + public @FloatRange(from = 0f, to = 100f) float getCpuHeadroom( + @Nullable CpuHeadroomParams params) { + if (mHintManager == null) { + throw new UnsupportedOperationException(); + } + try { + return mHintManager.getCpuHeadroom( + params != null ? params.getInternal() : new CpuHeadroomParamsInternal())[0]; + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + + + /** + * Provides an estimate of global available GPU headroom of the device. + * <p> + * + * @param params params to customize the GPU headroom calculation, null to use default params. + * @return a single value headroom or a {@code Float.NaN} if it's temporarily unavailable. + * A valid value is ranged from [0, 100], where 0 indicates no more GPU resources can be + * granted. + * @throws UnsupportedOperationException if the API is unsupported or the request params can't + * be served. + */ + @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS) + public @FloatRange(from = 0f, to = 100f) float getGpuHeadroom( + @Nullable GpuHeadroomParams params) { + if (mHintManager == null) { + throw new UnsupportedOperationException(); + } + try { + return mHintManager.getGpuHeadroom( + params != null ? params.getInternal() : new GpuHeadroomParamsInternal()); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Minimum polling interval for calling {@link #getCpuHeadroom(CpuHeadroomParams)} in + * milliseconds. + * <p> + * The {@link #getCpuHeadroom(CpuHeadroomParams)} API may return cached result if called more + * frequent than the interval. + * + * @throws UnsupportedOperationException if the API is unsupported. + */ + @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS) + public long getCpuHeadroomMinIntervalMillis() { + if (mHintManager == null) { + throw new UnsupportedOperationException(); + } + try { + return mHintManager.getCpuHeadroomMinIntervalMillis(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Minimum polling interval for calling {@link #getGpuHeadroom(GpuHeadroomParams)} in + * milliseconds. + * <p> + * The {@link #getGpuHeadroom(GpuHeadroomParams)} API may return cached result if called more + * frequent than the interval. + * + * @throws UnsupportedOperationException if the API is unsupported. + */ + @FlaggedApi(android.os.Flags.FLAG_CPU_GPU_HEADROOMS) + public long getGpuHeadroomMinIntervalMillis() { + if (mHintManager == null) { + throw new UnsupportedOperationException(); + } + try { + return mHintManager.getGpuHeadroomMinIntervalMillis(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } } /** @@ -261,7 +366,7 @@ public class SystemHealthManager { mPowerMonitorsInfo = result; } if (executor != null) { - executor.execute(()-> onResult.accept(result)); + executor.execute(() -> onResult.accept(result)); } else { onResult.accept(result); } diff --git a/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java b/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java index f2ad7a402b60..afaab55f4ed4 100644 --- a/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java +++ b/core/java/android/os/vibrator/VibratorEnvelopeEffectInfo.java @@ -34,11 +34,11 @@ import java.util.Objects; * </ul> * * <p>This information can be used to help construct waveform envelope effects with - * {@link VibrationEffect#startWaveformEnvelope()}. When designing these effects, it is also + * {@link VibrationEffect.WaveformEnvelopeBuilder}. When designing these effects, it is also * recommended to check the {@link VibratorFrequencyProfile} for information about the supported * frequency range and the vibrator's output response. * - * @see VibrationEffect#startWaveformEnvelope() + * @see VibrationEffect.WaveformEnvelopeBuilder * @see VibratorFrequencyProfile */ @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig index 6264fbbbcb7a..0a35fe399531 100644 --- a/core/java/android/permission/flags.aconfig +++ b/core/java/android/permission/flags.aconfig @@ -399,4 +399,13 @@ flag { namespace: "supervision" description: "This flag is used to enable all the remaining permissions required to the supervision role" bug: "367333883" -}
\ No newline at end of file +} + +flag { + name: "permission_request_short_circuit_enabled" + is_fixed_read_only: true + is_exported: true + namespace: "permissions" + description: "This flag is used to short circuit the request for permananently denied permissions" + bug: "378923900" +} diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig index ce901217d700..09004b3dcf03 100644 --- a/core/java/android/security/flags.aconfig +++ b/core/java/android/security/flags.aconfig @@ -115,6 +115,14 @@ flag { } flag { + name: "protect_device_config_flags" + namespace: "psap_ai" + description: "Feature flag to limit adb shell to allowlisted flags" + bug: "364083026" + is_fixed_read_only: true +} + +flag { name: "keystore_grant_api" namespace: "hardware_backed_security" description: "Feature flag for exposing KeyStore grant APIs" diff --git a/core/java/android/security/forensic/ForensicEvent.java b/core/java/android/security/forensic/ForensicEvent.java index 90906edcc636..3d908cca150c 100644 --- a/core/java/android/security/forensic/ForensicEvent.java +++ b/core/java/android/security/forensic/ForensicEvent.java @@ -17,13 +17,17 @@ package android.security.forensic; import android.annotation.FlaggedApi; +import android.annotation.IntDef; import android.annotation.NonNull; +import android.app.admin.ConnectEvent; +import android.app.admin.DnsEvent; +import android.app.admin.SecurityLog.SecurityEvent; import android.os.Parcel; import android.os.Parcelable; import android.security.Flags; -import android.util.ArrayMap; -import java.util.Map; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * A class that represents a forensic event. @@ -33,11 +37,24 @@ import java.util.Map; public final class ForensicEvent implements Parcelable { private static final String TAG = "ForensicEvent"; - @NonNull - private final String mType; + public static final int SECURITY_EVENT = 0; + public static final int NETWORK_EVENT_DNS = 1; + public static final int NETWORK_EVENT_CONNECT = 2; - @NonNull - private final Map<String, String> mKeyValuePairs; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + ForensicEvent.SECURITY_EVENT, + ForensicEvent.NETWORK_EVENT_DNS, + ForensicEvent.NETWORK_EVENT_CONNECT, + }) + public @interface EventType {} + + @NonNull @EventType private final int mType; + + private final SecurityEvent mSecurityEvent; + private final DnsEvent mNetworkEventDns; + private final ConnectEvent mNetworkEventConnect; public static final @NonNull Parcelable.Creator<ForensicEvent> CREATOR = new Parcelable.Creator<>() { @@ -50,30 +67,99 @@ public final class ForensicEvent implements Parcelable { } }; - public ForensicEvent(@NonNull String type, @NonNull Map<String, String> keyValuePairs) { - mType = type; - mKeyValuePairs = keyValuePairs; + public ForensicEvent(@NonNull SecurityEvent securityEvent) { + mType = SECURITY_EVENT; + mSecurityEvent = securityEvent; + mNetworkEventDns = null; + mNetworkEventConnect = null; + } + + public ForensicEvent(@NonNull DnsEvent dnsEvent) { + mType = NETWORK_EVENT_DNS; + mNetworkEventDns = dnsEvent; + mSecurityEvent = null; + mNetworkEventConnect = null; + } + + public ForensicEvent(@NonNull ConnectEvent connectEvent) { + mType = NETWORK_EVENT_CONNECT; + mNetworkEventConnect = connectEvent; + mSecurityEvent = null; + mNetworkEventDns = null; } private ForensicEvent(@NonNull Parcel in) { - mType = in.readString(); - mKeyValuePairs = new ArrayMap<>(in.readInt()); - in.readMap(mKeyValuePairs, getClass().getClassLoader(), String.class, String.class); + mType = in.readInt(); + switch (mType) { + case SECURITY_EVENT: + mSecurityEvent = SecurityEvent.CREATOR.createFromParcel(in); + mNetworkEventDns = null; + mNetworkEventConnect = null; + break; + case NETWORK_EVENT_DNS: + mNetworkEventDns = DnsEvent.CREATOR.createFromParcel(in); + mSecurityEvent = null; + mNetworkEventConnect = null; + break; + case NETWORK_EVENT_CONNECT: + mNetworkEventConnect = ConnectEvent.CREATOR.createFromParcel(in); + mSecurityEvent = null; + mNetworkEventDns = null; + break; + default: + throw new IllegalArgumentException("Invalid event type: " + mType); + } } - public String getType() { + /** Returns the type of the forensic event. */ + @NonNull + public @EventType int getType() { return mType; } - public Map<String, String> getKeyValuePairs() { - return mKeyValuePairs; + /** Returns the SecurityEvent object. */ + @NonNull + public SecurityEvent getSecurityEvent() { + if (mType == SECURITY_EVENT) { + return mSecurityEvent; + } + throw new IllegalArgumentException("Event type is not security event: " + mType); + } + + /** Returns the DnsEvent object. */ + @NonNull + public DnsEvent getDnsEvent() { + if (mType == NETWORK_EVENT_DNS) { + return mNetworkEventDns; + } + throw new IllegalArgumentException("Event type is not network DNS event: " + mType); + } + + /** Returns the ConnectEvent object. */ + @NonNull + public ConnectEvent getConnectEvent() { + if (mType == NETWORK_EVENT_CONNECT) { + return mNetworkEventConnect; + } + throw new IllegalArgumentException("Event type is not network connect event: " + mType); } @Override public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeString(mType); - out.writeInt(mKeyValuePairs.size()); - out.writeMap(mKeyValuePairs); + out.writeInt(mType); + switch (mType) { + case SECURITY_EVENT: + out.writeParcelable(mSecurityEvent, flags); + break; + case NETWORK_EVENT_DNS: + out.writeParcelable(mNetworkEventDns, flags); + break; + case NETWORK_EVENT_CONNECT: + out.writeParcelable(mNetworkEventConnect, flags); + break; + default: + throw new IllegalArgumentException("Invalid event type: " + mType); + } } @FlaggedApi(Flags.FLAG_AFL_API) @@ -86,7 +172,6 @@ public final class ForensicEvent implements Parcelable { public String toString() { return "ForensicEvent{" + "mType=" + mType - + ", mKeyValuePairs=" + mKeyValuePairs + '}'; } } diff --git a/core/java/android/security/forensic/ForensicManager.java b/core/java/android/security/forensic/ForensicManager.java new file mode 100644 index 000000000000..9126182eda7b --- /dev/null +++ b/core/java/android/security/forensic/ForensicManager.java @@ -0,0 +1,276 @@ +/* + * 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 android.security.forensic; + +import static android.Manifest.permission.MANAGE_FORENSIC_STATE; +import static android.Manifest.permission.READ_FORENSIC_STATE; + +import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.annotation.SystemService; +import android.content.Context; +import android.os.RemoteException; +import android.security.Flags; +import android.util.Log; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * ForensicManager manages the forensic logging on Android devices. + * Upon user consent, forensic logging collects various device events for + * off-device investigation of potential device compromise. + * <p> + * Forensic logging can either be enabled ({@link #STATE_ENABLED} + * or disabled ({@link #STATE_DISABLED}). + * <p> + * The Forensic logs will be transferred to + * {@link android.security.forensic.ForensicEventTransport}. + * + * @hide + */ +@SystemApi +@FlaggedApi(Flags.FLAG_AFL_API) +@SystemService(Context.FORENSIC_SERVICE) +public class ForensicManager { + private static final String TAG = "ForensicManager"; + + /** @hide */ + @Target(ElementType.TYPE_USE) + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "STATE_" }, value = { + STATE_UNKNOWN, + STATE_DISABLED, + STATE_ENABLED + }) + public @interface ForensicState {} + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "ERROR_" }, value = { + ERROR_UNKNOWN, + ERROR_PERMISSION_DENIED, + ERROR_TRANSPORT_UNAVAILABLE, + ERROR_DATA_SOURCE_UNAVAILABLE + }) + public @interface ForensicError {} + + /** + * Indicates an unknown state + */ + public static final int STATE_UNKNOWN = IForensicServiceStateCallback.State.UNKNOWN; + + /** + * Indicates an state that the forensic is turned off. + */ + public static final int STATE_DISABLED = IForensicServiceStateCallback.State.DISABLED; + + /** + * Indicates an state that the forensic is turned on. + */ + public static final int STATE_ENABLED = IForensicServiceStateCallback.State.ENABLED; + + /** + * Indicates an unknown error + */ + public static final int ERROR_UNKNOWN = IForensicServiceCommandCallback.ErrorCode.UNKNOWN; + + /** + * Indicates an error due to insufficient access rights. + */ + public static final int ERROR_PERMISSION_DENIED = + IForensicServiceCommandCallback.ErrorCode.PERMISSION_DENIED; + + /** + * Indicates an error due to unavailability of the forensic event transport. + */ + public static final int ERROR_TRANSPORT_UNAVAILABLE = + IForensicServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE; + + /** + * Indicates an error due to unavailability of the data source. + */ + public static final int ERROR_DATA_SOURCE_UNAVAILABLE = + IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE; + + + private final IForensicService mService; + + private final ConcurrentHashMap<Consumer<Integer>, IForensicServiceStateCallback> + mStateCallbacks = new ConcurrentHashMap<>(); + + /** + * Constructor + * + * @param service A valid instance of IForensicService. + * @hide + */ + public ForensicManager(IForensicService service) { + mService = service; + } + + /** + * Add a callback to monitor the state of the ForensicService. + * + * @param executor The executor through which the callback should be invoked. + * @param callback The callback for state change. + * Once the callback is registered, the callback will be called + * to reflect the init state. + * The callback can be registered only once. + */ + @RequiresPermission(READ_FORENSIC_STATE) + public void addStateCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull @ForensicState Consumer<Integer> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + if (mStateCallbacks.get(callback) != null) { + Log.d(TAG, "addStateCallback callback already present"); + return; + } + + final IForensicServiceStateCallback wrappedCallback = + new IForensicServiceStateCallback.Stub() { + @Override + public void onStateChange(int state) { + executor.execute(() -> callback.accept(state)); + } + }; + try { + mService.addStateCallback(wrappedCallback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + mStateCallbacks.put(callback, wrappedCallback); + } + + /** + * Remove a callback to monitor the state of the ForensicService. + * + * @param callback The callback to remove. + */ + @RequiresPermission(READ_FORENSIC_STATE) + public void removeStateCallback(@NonNull Consumer<@ForensicState Integer> callback) { + Objects.requireNonNull(callback); + if (!mStateCallbacks.containsKey(callback)) { + Log.d(TAG, "removeStateCallback callback not present"); + return; + } + + IForensicServiceStateCallback wrappedCallback = mStateCallbacks.get(callback); + + try { + mService.removeStateCallback(wrappedCallback); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + mStateCallbacks.remove(callback); + } + + /** + * Enable forensic logging. + * If successful, ForensicService will transition to {@link #STATE_ENABLED} state. + * <p> + * When forensic logging is enabled, various device events will be collected and + * sent over to the registered {@link android.security.forensic.ForensicEventTransport}. + * + * @param executor The executor through which the callback should be invoked. + * @param callback The callback for the command result. + */ + @RequiresPermission(MANAGE_FORENSIC_STATE) + public void enable(@NonNull @CallbackExecutor Executor executor, + @NonNull CommandCallback callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + try { + mService.enable(new IForensicServiceCommandCallback.Stub() { + @Override + public void onSuccess() { + executor.execute(callback::onSuccess); + } + + @Override + public void onFailure(int error) { + executor.execute(() -> callback.onFailure(error)); + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Disable forensic logging. + * If successful, ForensicService will transition to {@link #STATE_DISABLED}. + * <p> + * When forensic logging is disabled, device events will no longer be collected. + * Any events that have been collected but not yet sent to ForensicEventTransport + * will be transferred as a final batch. + * + * @param executor The executor through which the callback should be invoked. + * @param callback The callback for the command result. + */ + @RequiresPermission(MANAGE_FORENSIC_STATE) + public void disable(@NonNull @CallbackExecutor Executor executor, + @NonNull CommandCallback callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + try { + mService.disable(new IForensicServiceCommandCallback.Stub() { + @Override + public void onSuccess() { + executor.execute(callback::onSuccess); + } + + @Override + public void onFailure(int error) { + executor.execute(() -> callback.onFailure(error)); + } + }); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Callback used in {@link #enable} and {@link #disable} to indicate the result of the command. + */ + public interface CommandCallback { + /** + * Called when command succeeds. + */ + void onSuccess(); + + /** + * Called when command fails. + * @param error The error number. + */ + void onFailure(@ForensicError int error); + } +} diff --git a/core/java/android/security/forensic/IBackupTransport.aidl b/core/java/android/security/forensic/IForensicEventTransport.aidl index c2cbc83ba1b3..80e78eb9cf49 100644 --- a/core/java/android/security/forensic/IBackupTransport.aidl +++ b/core/java/android/security/forensic/IForensicEventTransport.aidl @@ -20,7 +20,7 @@ import android.security.forensic.ForensicEvent; import com.android.internal.infra.AndroidFuture; /** {@hide} */ -oneway interface IBackupTransport { +oneway interface IForensicEventTransport { /** * Initialize the server side. */ diff --git a/core/java/android/security/forensic/IForensicService.aidl b/core/java/android/security/forensic/IForensicService.aidl index a944b18cb26d..8039b264f0e5 100644 --- a/core/java/android/security/forensic/IForensicService.aidl +++ b/core/java/android/security/forensic/IForensicService.aidl @@ -24,9 +24,12 @@ import android.security.forensic.IForensicServiceStateCallback; * @hide */ interface IForensicService { - void monitorState(IForensicServiceStateCallback callback); - void makeVisible(IForensicServiceCommandCallback callback); - void makeInvisible(IForensicServiceCommandCallback callback); + @EnforcePermission("READ_FORENSIC_STATE") + void addStateCallback(IForensicServiceStateCallback callback); + @EnforcePermission("READ_FORENSIC_STATE") + void removeStateCallback(IForensicServiceStateCallback callback); + @EnforcePermission("MANAGE_FORENSIC_STATE") void enable(IForensicServiceCommandCallback callback); + @EnforcePermission("MANAGE_FORENSIC_STATE") void disable(IForensicServiceCommandCallback callback); } diff --git a/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl b/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl index 7fa0c7f72690..6d1456ea0426 100644 --- a/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl +++ b/core/java/android/security/forensic/IForensicServiceCommandCallback.aidl @@ -25,8 +25,8 @@ package android.security.forensic; UNKNOWN = 0, PERMISSION_DENIED = 1, INVALID_STATE_TRANSITION = 2, - BACKUP_TRANSPORT_UNAVAILABLE = 3, - DATA_SOURCE_UNAVAILABLE = 3, + TRANSPORT_UNAVAILABLE = 3, + DATA_SOURCE_UNAVAILABLE = 4, } void onSuccess(); void onFailure(ErrorCode error); diff --git a/core/java/android/security/forensic/IForensicServiceStateCallback.aidl b/core/java/android/security/forensic/IForensicServiceStateCallback.aidl index 0cda35083ffd..1b68c7b14bca 100644 --- a/core/java/android/security/forensic/IForensicServiceStateCallback.aidl +++ b/core/java/android/security/forensic/IForensicServiceStateCallback.aidl @@ -23,9 +23,8 @@ package android.security.forensic; @Backing(type="int") enum State{ UNKNOWN = 0, - INVISIBLE = 1, - VISIBLE = 2, - ENABLED = 3, + DISABLED = 1, + ENABLED = 2, } void onStateChange(State state); } diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java index 98dda1031eff..14a14e69f208 100644 --- a/core/java/android/service/autofill/FillEventHistory.java +++ b/core/java/android/service/autofill/FillEventHistory.java @@ -16,8 +16,10 @@ package android.service.autofill; +import static android.service.autofill.Flags.FLAG_AUTOFILL_W_METRICS; import static android.view.autofill.Helper.sVerbose; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -63,14 +65,21 @@ public final class FillEventHistory implements Parcelable { private static final String TAG = "FillEventHistory"; /** - * Not in parcel. The ID of the autofill session that created the {@link FillResponse}. + * The ID of the autofill session that created the {@link FillResponse}. + * + * TODO: add this to the parcel. */ private final int mSessionId; @Nullable private final Bundle mClientState; @Nullable List<Event> mEvents; - /** @hide */ + /** + * Returns the unique identifier of this FillEventHistory. + * + * <p>This is used to differentiate individual FillEventHistory. + */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) public int getSessionId() { return mSessionId; } @@ -283,6 +292,13 @@ public final class FillEventHistory implements Parcelable { /** All fields matched contents of datasets. */ public static final int NO_SAVE_UI_REASON_DATASET_MATCH = 6; + /** + * Credential Manager is invoked instead of Autofill. When that happens, Save Dialog cannot + * be shown, and this will be populated in + */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + public static final int NO_SAVE_UI_REASON_USING_CREDMAN = 7; + /** @hide */ @IntDef(prefix = { "NO_SAVE_UI_REASON_" }, value = { NO_SAVE_UI_REASON_NONE, @@ -310,11 +326,20 @@ public final class FillEventHistory implements Parcelable { public static final int UI_TYPE_DIALOG = 3; /** - * The autofill suggestion is shown os a credman bottom sheet - * @hide + * The autofill suggestion is shown os a credman bottom sheet + * + * <p>Note, this was introduced as bottom sheet even though it applies to all credman UI + * types. Instead of exposing this directly to the public, the generic UI_TYPE_CREDMAN is + * introduced with the same number. + * + * @hide */ public static final int UI_TYPE_CREDMAN_BOTTOM_SHEET = 4; + /** Credential Manager suggestions are shown instead of Autofill suggestion */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + public static final int UI_TYPE_CREDMAN = 4; + /** @hide */ @IntDef(prefix = { "UI_TYPE_" }, value = { UI_TYPE_UNKNOWN, @@ -359,6 +384,13 @@ public final class FillEventHistory implements Parcelable { return mEventType; } + /** Gets the {@code AutofillId} that's focused at the time of action */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + @Nullable + public AutofillId getFocusedId() { + return null; + } + /** * Returns the id of dataset the id was on. * @@ -391,6 +423,17 @@ public final class FillEventHistory implements Parcelable { } /** + * Returns which datasets were shown to the user. + * + * <p><b>Note: </b>Only set on events of type {@link #TYPE_DATASETS_SHOWN}. + */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + @NonNull + public Set<String> getShownDatasetIds() { + return Collections.emptySet(); + } + + /** * Returns which datasets were NOT selected by the user. * * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}. diff --git a/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl b/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl index 0dca78d890a5..03e27b866b7a 100644 --- a/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl +++ b/core/java/android/service/quickaccesswallet/IQuickAccessWalletService.aidl @@ -43,4 +43,6 @@ interface IQuickAccessWalletService { oneway void unregisterWalletServiceEventListener(in WalletServiceEventListenerRequest request); // Request to get a PendingIntent to launch an activity from which the user can manage their cards. oneway void onTargetActivityIntentRequested(in IQuickAccessWalletServiceCallbacks callbacks); + // Request to get a PendingIntent to launch an activity, triggered when the user performs a gesture. + oneway void onGestureTargetActivityIntentRequested(in IQuickAccessWalletServiceCallbacks callbacks); }
\ No newline at end of file diff --git a/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl b/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl index 1b69ca12da3a..61d7fd1f526c 100644 --- a/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl +++ b/core/java/android/service/quickaccesswallet/IQuickAccessWalletServiceCallbacks.aidl @@ -37,4 +37,6 @@ interface IQuickAccessWalletServiceCallbacks { oneway void onWalletServiceEvent(in WalletServiceEvent event); // Called in response to onTargetActivityIntentRequested. May only be called once per request. oneway void onTargetActivityPendingIntentReceived(in PendingIntent pendingIntent); + //Called in response to onGesturePendingIntent + oneway void onGestureTargetActivityPendingIntentReceived(in PendingIntent pendingIntent); }
\ No newline at end of file diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java index faa5b2fe3488..b5251db4e539 100644 --- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java +++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClient.java @@ -17,6 +17,7 @@ package android.service.quickaccesswallet; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; @@ -181,6 +182,23 @@ public interface QuickAccessWalletClient extends Closeable { } /** + * Gets the {@link PendingIntent} provided by QuickAccessWalletService to be sent when the user + * launches Wallet via gesture. + */ + @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + void getGestureTargetActivityPendingIntent( + @NonNull @CallbackExecutor Executor executor, + @NonNull GesturePendingIntentCallback gesturePendingIntentCallback); + + /** Callback interface for getGesturePendingIntent. */ + @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + interface GesturePendingIntentCallback { + /** Callback method for getGesturePendingIntent */ + @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + void onGesturePendingIntentRetrieved(@Nullable PendingIntent pendingIntent); + } + + /** * The manifest entry for the QuickAccessWalletService may also publish information about the * activity that hosts the Wallet view. This is typically the home screen of the Wallet * application. diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java index a59f026c4182..97a4beff633f 100644 --- a/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java +++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletClientImpl.java @@ -267,6 +267,34 @@ public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Ser } @Override + public void getGestureTargetActivityPendingIntent( + @NonNull @CallbackExecutor Executor executor, + @NonNull GesturePendingIntentCallback gesturePendingIntentCallback) { + BaseCallbacks callbacks = + new BaseCallbacks() { + @Override + public void onGestureTargetActivityPendingIntentReceived( + PendingIntent pendingIntent) { + if (!Flags.launchWalletOptionOnPowerDoubleTap()) { + return; + } + executor.execute( + () -> + gesturePendingIntentCallback + .onGesturePendingIntentRetrieved(pendingIntent)); + } + }; + + executeApiCall( + new ApiCaller("getGestureTargetActivityPendingIntent") { + @Override + void performApiCall(IQuickAccessWalletService service) throws RemoteException { + service.onGestureTargetActivityIntentRequested(callbacks); + } + }); + } + + @Override @Nullable public Intent createWalletSettingsIntent() { if (mServiceInfo == null) { @@ -506,5 +534,9 @@ public class QuickAccessWalletClientImpl implements QuickAccessWalletClient, Ser public void onTargetActivityPendingIntentReceived(PendingIntent pendingIntent) { throw new IllegalStateException(); } + + public void onGestureTargetActivityPendingIntentReceived(PendingIntent pendingIntent) { + throw new IllegalStateException(); + } } } diff --git a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java index 36fa21c19d27..90136ae00f6a 100644 --- a/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java +++ b/core/java/android/service/quickaccesswallet/QuickAccessWalletService.java @@ -16,6 +16,9 @@ package android.service.quickaccesswallet; +import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap; + +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; @@ -247,6 +250,19 @@ public abstract class QuickAccessWalletService extends Service { callbacks)); } + @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + @Override + public void onGestureTargetActivityIntentRequested( + @NonNull IQuickAccessWalletServiceCallbacks callbacks) { + if (launchWalletOptionOnPowerDoubleTap()) { + mHandler.post( + () -> + QuickAccessWalletService.this + .onGestureTargetActivityIntentRequestedInternal( + callbacks)); + } + } + public void registerWalletServiceEventListener( @NonNull WalletServiceEventListenerRequest request, @NonNull IQuickAccessWalletServiceCallbacks callback) { @@ -275,6 +291,20 @@ public abstract class QuickAccessWalletService extends Service { } } + private void onGestureTargetActivityIntentRequestedInternal( + IQuickAccessWalletServiceCallbacks callbacks) { + if (!Flags.launchWalletOptionOnPowerDoubleTap()) { + return; + } + + try { + callbacks.onGestureTargetActivityPendingIntentReceived( + getGestureTargetActivityPendingIntent()); + } catch (RemoteException e) { + Log.w(TAG, "Error", e); + } + } + @Override @Nullable public IBinder onBind(@NonNull Intent intent) { @@ -349,6 +379,18 @@ public abstract class QuickAccessWalletService extends Service { return null; } + /** + * Specify a {@link PendingIntent} to be launched on user gesture. + * + * <p>The pending intent will be sent when the user performs a gesture to open Wallet. + * The pending intent should launch an activity. + */ + @Nullable + @FlaggedApi(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public PendingIntent getGestureTargetActivityPendingIntent() { + return null; + } + private void sendWalletServiceEventInternal(WalletServiceEvent serviceEvent) { if (mEventListener == null) { Log.i(TAG, "No dismiss listener registered"); diff --git a/core/java/android/service/quickaccesswallet/flags.aconfig b/core/java/android/service/quickaccesswallet/flags.aconfig index 07311d5ffbe1..75a93091eec3 100644 --- a/core/java/android/service/quickaccesswallet/flags.aconfig +++ b/core/java/android/service/quickaccesswallet/flags.aconfig @@ -3,7 +3,7 @@ container: "system" flag { name: "launch_wallet_option_on_power_double_tap" - namespace: "wallet_integrations" + namespace: "wallet_integration" description: "Option to launch the Wallet app on double-tap of the power button" bug: "378469025" }
\ No newline at end of file diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index 1df3b4332754..c16a510ed729 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -1712,6 +1712,15 @@ public class PhoneStateListener { @NonNull NtnSignalStrength ntnSignalStrength) { // not supported on the deprecated interface - Use TelephonyCallback instead } + + public final void onSecurityAlgorithmsChanged(SecurityAlgorithmUpdate update) { + // not supported on the deprecated interface - Use TelephonyCallback instead + } + + public final void onCellularIdentifierDisclosedChanged( + CellularIdentifierDisclosure disclosure) { + // not supported on the deprecated interface - Use TelephonyCallback instead + } } private void log(String s) { diff --git a/core/java/android/telephony/SubscriptionPlan.java b/core/java/android/telephony/SubscriptionPlan.java index 7b48a16c2227..4c59a8589df2 100644 --- a/core/java/android/telephony/SubscriptionPlan.java +++ b/core/java/android/telephony/SubscriptionPlan.java @@ -18,6 +18,7 @@ package android.telephony; import android.annotation.BytesLong; import android.annotation.CurrentTimeMillisLong; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -28,6 +29,7 @@ import android.telephony.Annotation.NetworkType; import android.util.Range; import android.util.RecurrenceRule; +import com.android.internal.telephony.flags.Flags; import com.android.internal.util.Preconditions; import java.lang.annotation.Retention; @@ -83,6 +85,33 @@ public final class SubscriptionPlan implements Parcelable { /** Value indicating a timestamp is unknown. */ public static final long TIME_UNKNOWN = -1; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "SUBSCRIPTION_STATUS_" }, value = { + SUBSCRIPTION_STATUS_UNKNOWN, + SUBSCRIPTION_STATUS_ACTIVE, + SUBSCRIPTION_STATUS_INACTIVE, + SUBSCRIPTION_STATUS_TRIAL, + SUBSCRIPTION_STATUS_SUSPENDED + }) + public @interface SubscriptionStatus {} + + /** Subscription status is unknown. */ + @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE) + public static final int SUBSCRIPTION_STATUS_UNKNOWN = 0; + /** Subscription is active. */ + @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE) + public static final int SUBSCRIPTION_STATUS_ACTIVE = 1; + /** Subscription is inactive. */ + @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE) + public static final int SUBSCRIPTION_STATUS_INACTIVE = 2; + /** Subscription is in a trial period. */ + @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE) + public static final int SUBSCRIPTION_STATUS_TRIAL = 3; + /** Subscription is suspended. */ + @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE) + public static final int SUBSCRIPTION_STATUS_SUSPENDED = 4; + private final RecurrenceRule cycleRule; private CharSequence title; private CharSequence summary; @@ -91,6 +120,7 @@ public final class SubscriptionPlan implements Parcelable { private long dataUsageBytes = BYTES_UNKNOWN; private long dataUsageTime = TIME_UNKNOWN; private @NetworkType int[] networkTypes; + private int mSubscriptionStatus = SUBSCRIPTION_STATUS_UNKNOWN; private SubscriptionPlan(RecurrenceRule cycleRule) { this.cycleRule = Preconditions.checkNotNull(cycleRule); @@ -107,6 +137,7 @@ public final class SubscriptionPlan implements Parcelable { dataUsageBytes = source.readLong(); dataUsageTime = source.readLong(); networkTypes = source.createIntArray(); + mSubscriptionStatus = source.readInt(); } @Override @@ -124,6 +155,7 @@ public final class SubscriptionPlan implements Parcelable { dest.writeLong(dataUsageBytes); dest.writeLong(dataUsageTime); dest.writeIntArray(networkTypes); + dest.writeInt(mSubscriptionStatus); } @Override @@ -137,13 +169,14 @@ public final class SubscriptionPlan implements Parcelable { .append(" dataUsageBytes=").append(dataUsageBytes) .append(" dataUsageTime=").append(dataUsageTime) .append(" networkTypes=").append(Arrays.toString(networkTypes)) + .append(" subscriptionStatus=").append(mSubscriptionStatus) .append("}").toString(); } @Override public int hashCode() { return Objects.hash(cycleRule, title, summary, dataLimitBytes, dataLimitBehavior, - dataUsageBytes, dataUsageTime, Arrays.hashCode(networkTypes)); + dataUsageBytes, dataUsageTime, Arrays.hashCode(networkTypes), mSubscriptionStatus); } @Override @@ -157,7 +190,8 @@ public final class SubscriptionPlan implements Parcelable { && dataLimitBehavior == other.dataLimitBehavior && dataUsageBytes == other.dataUsageBytes && dataUsageTime == other.dataUsageTime - && Arrays.equals(networkTypes, other.networkTypes); + && Arrays.equals(networkTypes, other.networkTypes) + && mSubscriptionStatus == other.mSubscriptionStatus; } return false; } @@ -179,6 +213,13 @@ public final class SubscriptionPlan implements Parcelable { return cycleRule; } + /** Return the end date of this plan, or null if no end date exists. */ + @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE) + public @Nullable ZonedDateTime getPlanEndDate() { + // ZonedDateTime is immutable, so no need to create a defensive copy. + return cycleRule.end; + } + /** Return the short title of this plan. */ public @Nullable CharSequence getTitle() { return title; @@ -238,6 +279,16 @@ public final class SubscriptionPlan implements Parcelable { } /** + * Returns the status of the subscription plan. + * + * @return The subscription status, or {@link #SUBSCRIPTION_STATUS_UNKNOWN} if not available. + */ + @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE) + public @SubscriptionStatus int getSubscriptionStatus() { + return mSubscriptionStatus; + } + + /** * Builder for a {@link SubscriptionPlan}. */ public static class Builder { @@ -382,5 +433,21 @@ public final class SubscriptionPlan implements Parcelable { TelephonyManager.getAllNetworkTypes().length); return this; } + + /** + * Set the subscription status. + * + * @param subscriptionStatus the current subscription status + */ + @FlaggedApi(Flags.FLAG_SUBSCRIPTION_PLAN_ALLOW_STATUS_AND_END_DATE) + public @NonNull Builder setSubscriptionStatus(@SubscriptionStatus int subscriptionStatus) { + if (subscriptionStatus < SUBSCRIPTION_STATUS_UNKNOWN + || subscriptionStatus > SUBSCRIPTION_STATUS_SUSPENDED) { + throw new IllegalArgumentException( + "Subscription status must be defined with a valid value"); + } + plan.mSubscriptionStatus = subscriptionStatus; + return this; + } } } diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java index 0d1dc4611343..2c585e640fdd 100644 --- a/core/java/android/telephony/TelephonyCallback.java +++ b/core/java/android/telephony/TelephonyCallback.java @@ -705,6 +705,28 @@ public class TelephonyCallback { public static final int EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED = 45; /** + * Event for changes to mobile network ciphering algorithms. + * See {@link SecurityAlgorithmsListener#onSecurityAlgorithmsChanged} + * + * @hide + */ + @FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS) + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SystemApi + public static final int EVENT_SECURITY_ALGORITHMS_CHANGED = 46; + + /** + * Event for updates to sensitive device identifier disclosures (IMSI, IMEI, unciphered SUCI). + * See {@link CellularIdentifierDisclosedListener#onCellularIdentifierDisclosedChanged} + * + * @hide + */ + @FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS) + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SystemApi + public static final int EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED = 47; + + /** * @hide */ @IntDef(prefix = {"EVENT_"}, value = { @@ -752,7 +774,9 @@ public class TelephonyCallback { EVENT_CARRIER_ROAMING_NTN_MODE_CHANGED, EVENT_CARRIER_ROAMING_NTN_ELIGIBLE_STATE_CHANGED, EVENT_CARRIER_ROAMING_NTN_AVAILABLE_SERVICES_CHANGED, - EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED + EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED, + EVENT_SECURITY_ALGORITHMS_CHANGED, + EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED }) @Retention(RetentionPolicy.SOURCE) public @interface TelephonyEvent { @@ -1827,6 +1851,41 @@ public class TelephonyCallback { } /** + * Interface for CellularIdentifierDisclosedListener + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS) + public interface CellularIdentifierDisclosedListener { + /** + * Callback invoked when a device identifier (IMSI, IMEI, or unciphered SUCI) + * is disclosed over the network before a security context is established + * ("pre-authentication"). + * + * @param disclosure details of the identifier disclosure + * See {@link CellularIdentifierDisclosure} for more details + */ + void onCellularIdentifierDisclosedChanged(@NonNull CellularIdentifierDisclosure disclosure); + } + + /** + * Interface for SecurityAlgorithmsListener + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_SECURITY_ALGORITHMS_UPDATE_INDICATIONS) + public interface SecurityAlgorithmsListener { + /** + * Callback invoked when the most recently reported security algorithms has changed, + * per a specified connection event. + * + * @param securityAlgorithmUpdate details of the security algorithm update + * See {@link SecurityAlgorithmUpdate} for more details + */ + void onSecurityAlgorithmsChanged(@NonNull SecurityAlgorithmUpdate securityAlgorithmUpdate); + } + + /** * The callback methods need to be called on the handler thread where * this object was created. If the binder did that for us it'd be nice. * <p> @@ -2302,5 +2361,27 @@ public class TelephonyCallback { () -> listener.onCarrierRoamingNtnSignalStrengthChanged(ntnSignalStrength))); } + + public void onSecurityAlgorithmsChanged(SecurityAlgorithmUpdate update) { + if (!Flags.securityAlgorithmsUpdateIndications()) return; + + SecurityAlgorithmsListener listener = + (SecurityAlgorithmsListener) mTelephonyCallbackWeakRef.get(); + if (listener == null) return; + + Binder.withCleanCallingIdentity(() -> mExecutor.execute( + () -> listener.onSecurityAlgorithmsChanged(update))); + } + + public void onCellularIdentifierDisclosedChanged(CellularIdentifierDisclosure disclosure) { + if (!Flags.cellularIdentifierDisclosureIndications()) return; + + CellularIdentifierDisclosedListener listener = + (CellularIdentifierDisclosedListener) mTelephonyCallbackWeakRef.get(); + if (listener == null) return; + + Binder.withCleanCallingIdentity(() -> mExecutor.execute( + () -> listener.onCellularIdentifierDisclosedChanged(disclosure))); + } } } diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java index 90b0bb34c145..4ec429d0c4ad 100644 --- a/core/java/android/telephony/TelephonyRegistryManager.java +++ b/core/java/android/telephony/TelephonyRegistryManager.java @@ -1154,6 +1154,40 @@ public class TelephonyRegistryManager { } } + /** + * Notify external listeners that the radio security algorithms have changed. + * @param slotIndex for the phone object that got updated + * @param subId for which the security algorithm changed + * @param update details of the security algorithm update + * @hide + */ + public void notifySecurityAlgorithmsChanged( + int slotIndex, int subId, SecurityAlgorithmUpdate update) { + try { + sRegistry.notifySecurityAlgorithmsChanged(slotIndex, subId, update); + } catch (RemoteException ex) { + // system server crash + throw ex.rethrowFromSystemServer(); + } + } + + /** + * Notify external listeners of a new cellular identifier disclosure change. + * @param slotIndex for the phone object that the disclosure applies to + * @param subId for which the disclosure applies to + * @param disclosure details of the identifier disclosure + * @hide + */ + public void notifyCellularIdentifierDisclosedChanged( + int slotIndex, int subId, CellularIdentifierDisclosure disclosure) { + try { + sRegistry.notifyCellularIdentifierDisclosedChanged(slotIndex, subId, disclosure); + } catch (RemoteException ex) { + // system server crash + throw ex.rethrowFromSystemServer(); + } + } + /** * Processes potential event changes from the provided {@link TelephonyCallback}. * @@ -1313,6 +1347,15 @@ public class TelephonyRegistryManager { eventList.add(TelephonyCallback.EVENT_CARRIER_ROAMING_NTN_AVAILABLE_SERVICES_CHANGED); eventList.add(TelephonyCallback.EVENT_CARRIER_ROAMING_NTN_SIGNAL_STRENGTH_CHANGED); } + + if (telephonyCallback instanceof TelephonyCallback.CellularIdentifierDisclosedListener) { + eventList.add(TelephonyCallback.EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED); + } + + if (telephonyCallback instanceof TelephonyCallback.SecurityAlgorithmsListener) { + eventList.add(TelephonyCallback.EVENT_SECURITY_ALGORITHMS_CHANGED); + } + return eventList; } diff --git a/core/java/android/text/TextFlags.java b/core/java/android/text/TextFlags.java deleted file mode 100644 index f69a333ff81f..000000000000 --- a/core/java/android/text/TextFlags.java +++ /dev/null @@ -1,81 +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 android.text; - -import android.annotation.NonNull; -import android.app.AppGlobals; - -/** - * Flags in the "text" namespace. - * - * TODO(nona): Remove this class. - * @hide - */ -public final class TextFlags { - - /** - * The name space of the "text" feature. - * - * This needs to move to DeviceConfig constant. - */ - public static final String NAMESPACE = "text"; - - /** - * Whether we use the new design of context menu. - */ - public static final String ENABLE_NEW_CONTEXT_MENU = - "TextEditing__enable_new_context_menu"; - - /** - * The key name used in app core settings for {@link #ENABLE_NEW_CONTEXT_MENU}. - */ - public static final String KEY_ENABLE_NEW_CONTEXT_MENU = "text__enable_new_context_menu"; - - /** - * Default value for the flag {@link #ENABLE_NEW_CONTEXT_MENU}. - */ - public static final boolean ENABLE_NEW_CONTEXT_MENU_DEFAULT = true; - - /** - * List of text flags to be transferred to the application process. - */ - public static final String[] TEXT_ACONFIGS_FLAGS = { - }; - - /** - * List of the default values of the text flags. - * - * The order must be the same to the TEXT_ACONFIG_FLAGS. - */ - public static final boolean[] TEXT_ACONFIG_DEFAULT_VALUE = { - }; - - /** - * Get a key for the feature flag. - */ - public static String getKeyForFlag(@NonNull String flag) { - return "text__" + flag; - } - - /** - * Return true if the feature flag is enabled. - */ - public static boolean isFeatureEnabled(@NonNull String flag) { - return AppGlobals.getIntCoreSetting( - getKeyForFlag(flag), 0 /* aconfig is false by default */) != 0; - } -} diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index 032f5923d3f2..cb72b976c784 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -50,6 +50,7 @@ import android.text.style.LineBackgroundSpan; import android.text.style.LineBreakConfigSpan; import android.text.style.LineHeightSpan; import android.text.style.LocaleSpan; +import android.text.style.NoWritingToolsSpan; import android.text.style.ParagraphStyle; import android.text.style.QuoteSpan; import android.text.style.RelativeSizeSpan; @@ -817,7 +818,9 @@ public class TextUtils { /** @hide */ public static final int LINE_BREAK_CONFIG_SPAN = 30; /** @hide */ - public static final int LAST_SPAN = LINE_BREAK_CONFIG_SPAN; + public static final int NO_WRITING_TOOLS_SPAN = 31; + /** @hide */ + public static final int LAST_SPAN = NO_WRITING_TOOLS_SPAN; /** * Flatten a CharSequence and whatever styles can be copied across processes @@ -1025,6 +1028,10 @@ public class TextUtils { span = LineBreakConfigSpan.CREATOR.createFromParcel(p); break; + case NO_WRITING_TOOLS_SPAN: + span = NoWritingToolsSpan.CREATOR.createFromParcel(p); + break; + default: throw new RuntimeException("bogus span encoding " + kind); } diff --git a/core/java/android/text/style/NoWritingToolsSpan.java b/core/java/android/text/style/NoWritingToolsSpan.java new file mode 100644 index 000000000000..90f85aa69faa --- /dev/null +++ b/core/java/android/text/style/NoWritingToolsSpan.java @@ -0,0 +1,87 @@ +/* + * 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 android.text.style; + +import static android.view.inputmethod.Flags.FLAG_WRITING_TOOLS; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; +import android.os.Parcel; +import android.text.ParcelableSpan; +import android.text.TextUtils; + +/** + * A span that signals to IMEs that writing tools should not modify the text. + * + * <p>For example, a text field may contain a mix of user input text and quoted text. The app + * can apply {@code NoWritingToolsSpan} to the quoted text so that the IME knows that writing + * tools should only rewrite the user input text, and not modify the quoted text. + */ +@FlaggedApi(FLAG_WRITING_TOOLS) +public final class NoWritingToolsSpan implements ParcelableSpan { + + /** + * Creates a {@link NoWritingToolsSpan}. + */ + public NoWritingToolsSpan() { + } + + @Override + public int getSpanTypeId() { + return getSpanTypeIdInternal(); + } + + /** @hide */ + @Override + public int getSpanTypeIdInternal() { + return TextUtils.NO_WRITING_TOOLS_SPAN; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + writeToParcelInternal(dest, flags); + } + + /** @hide */ + @Override + public void writeToParcelInternal(@NonNull Parcel dest, int flags) { + } + + @Override + public String toString() { + return "NoWritingToolsSpan{}"; + } + + @NonNull + public static final Creator<NoWritingToolsSpan> CREATOR = new Creator<>() { + + @Override + public NoWritingToolsSpan createFromParcel(Parcel source) { + return new NoWritingToolsSpan(); + } + + @Override + public NoWritingToolsSpan[] newArray(int size) { + return new NoWritingToolsSpan[size]; + } + }; +} diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 5a71282dab0a..8cb96ae1d611 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -930,8 +930,8 @@ public final class Choreographer { // of the next vsync event. int totalFrameDelays = mBufferStuffingData.numberFrameDelays + mBufferStuffingData.numberWaitsForNextVsync + 1; - long vsyncsSinceLastCallback = - (frameTimeNanos - mLastNoOffsetFrameTimeNanos) / mLastFrameIntervalNanos; + long vsyncsSinceLastCallback = mLastFrameIntervalNanos > 0 + ? (frameTimeNanos - mLastNoOffsetFrameTimeNanos) / mLastFrameIntervalNanos : 0; // Detected idle state due to a longer inactive period since the last vsync callback // than the total expected number of vsync frame delays. End buffer stuffing recovery. diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 5a28d5f7fc01..80ae3c3d4e73 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -437,16 +437,16 @@ public class ScaleGestureDetector { } } - /** - * Return whether the quick scale gesture, in which the user performs a double tap followed by a - * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}. - */ + /** + * Return whether the quick scale gesture, in which the user performs a double tap followed by a + * swipe, should perform scaling. {@see #setQuickScaleEnabled(boolean)}. + */ public boolean isQuickScaleEnabled() { return mQuickScaleEnabled; } /** - * Sets whether the associates {@link OnScaleGestureListener} should receive + * Sets whether the associated {@link OnScaleGestureListener} should receive * onScale callbacks when the user uses a stylus and presses the button. * Note that this is enabled by default if the app targets API 23 and newer. * diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index 68efa79715a3..d56768d2db03 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -4566,14 +4566,31 @@ public final class SurfaceControl implements Parcelable { return this; } - /** @hide */ + /** + * Sets the Luts for the layer. + * + * <p> The function also allows to clear previously applied lut(s). To do this, + * set the displayluts to be either {@code nullptr} or + * an empty {@link android.hardware.DisplayLuts} instance. + * + * @param sc The SurfaceControl to update + * + * @param displayLuts The selected Lut(s) + * + * @return this + * @see DisplayLuts + */ + @FlaggedApi(android.hardware.flags.Flags.FLAG_LUTS_API) public @NonNull Transaction setLuts(@NonNull SurfaceControl sc, - @NonNull DisplayLuts displayLuts) { + @Nullable DisplayLuts displayLuts) { checkPreconditions(sc); - - nativeSetLuts(mNativeObject, sc.mNativeObject, displayLuts.getLutBuffers(), - displayLuts.getOffsets(), displayLuts.getLutDimensions(), - displayLuts.getLutSizes(), displayLuts.getLutSamplingKeys()); + if (displayLuts != null && displayLuts.valid()) { + nativeSetLuts(mNativeObject, sc.mNativeObject, displayLuts.getLutBuffers(), + displayLuts.getOffsets(), displayLuts.getLutDimensions(), + displayLuts.getLutSizes(), displayLuts.getLutSamplingKeys()); + } else { + nativeSetLuts(mNativeObject, sc.mNativeObject, null, null, null, null, null); + } return this; } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index e50662adc3f1..19d3dc4df04e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -2516,6 +2516,11 @@ public final class ViewRootImpl implements ViewParent, public void notifyInsetsAnimationRunningStateChanged(boolean running) { if (sToolkitSetFrameRateReadOnlyFlagValue) { mInsetsAnimationRunning = running; + if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { + Trace.instant(Trace.TRACE_TAG_VIEW, + TextUtils.formatSimple("notifyInsetsAnimationRunningStateChanged(%s)", + Boolean.toString(running))); + } } } diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java index 1af9387e6fbd..1be7f4849f07 100644 --- a/core/java/android/view/ViewStructure.java +++ b/core/java/android/view/ViewStructure.java @@ -17,6 +17,7 @@ package android.view; import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION; +import static android.service.autofill.Flags.FLAG_AUTOFILL_W_METRICS; import android.annotation.FlaggedApi; import android.annotation.NonNull; @@ -79,27 +80,24 @@ public abstract class ViewStructure { * Key used for writing the type of the view that generated the virtual structure of its * children. * - * For example, if the virtual structure is generated by a webview, the value would be + * <p>For example, if the virtual structure is generated by a webview, the value would be * "WebView". If the virtual structure is generated by a compose view, then the value would be * "ComposeView". The value is of type String. * - * This value is added to mainly help with debugging purpose. - * - * @hide + * <p>This value is added to mainly help with debugging purpose. */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) public static final String EXTRA_VIRTUAL_STRUCTURE_TYPE = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_TYPE"; - /** * Key used for specifying the version of the view that generated the virtual structure for * itself and its children * - * For example, if the virtual structure is generated by a webview of version "104.0.5112.69", - * then the value should be "104.0.5112.69" - * - * @hide + * <p>For example, if the virtual structure is generated by a webview of version + * "104.0.5112.69", then the value should be "104.0.5112.69" */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) public static final String EXTRA_VIRTUAL_STRUCTURE_VERSION_NUMBER = "android.view.ViewStructure.extra.VIRTUAL_STRUCTURE_VERSION_NUMBER"; diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java index 6b608582c1dd..bd277784c1d3 100644 --- a/core/java/android/view/autofill/AutofillId.java +++ b/core/java/android/view/autofill/AutofillId.java @@ -15,6 +15,9 @@ */ package android.view.autofill; +import static android.service.autofill.Flags.FLAG_AUTOFILL_W_METRICS; + +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; @@ -111,12 +114,43 @@ public final class AutofillId implements Parcelable { return new AutofillId(flags, id.mViewId, virtualChildId, NO_SESSION); } - /** @hide */ + /** + * Returns the assigned unique identifier of this AutofillID. + * + * See @link{android.view.View#getAutofillId()} for more information on + * how this is generated for native Views. + */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) public int getViewId() { return mViewId; } /** + * Gets the virtual id. This is set if the view is a virtual view, most commonly set if the View + * is of {@link android.webkit.WebView}. + */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + public int getAutofillVirtualId() { + return mVirtualIntId; + } + + /** Checks whether this AutofillId represents a virtual view. */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + public boolean isVirtual() { + return !isNonVirtual(); + } + + /** + * Checks if this node is generate as part of a {@link android.app.assist.AssistStructure}. This + * will usually return true if it should be used by an autofill service provider, and false + * otherwise. + */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) + public boolean isInAutofillSession() { + return hasSession(); + } + + /** * Gets the virtual child id. * * <p>Should only be used on subsystems where such id is represented by an {@code int} @@ -181,7 +215,12 @@ public final class AutofillId implements Parcelable { return (mFlags & FLAG_HAS_SESSION) != 0; } - /** @hide */ + /** + * Used to get the Session identifier associated with this AutofillId. + * + * @return a non-zero integer if {@link #isInAutofillSession()} returns true + */ + @FlaggedApi(FLAG_AUTOFILL_W_METRICS) public int getSessionId() { return mSessionId; } diff --git a/core/java/android/view/flags/scroll_feedback_flags.aconfig b/core/java/android/view/flags/scroll_feedback_flags.aconfig index b180e58cbe49..ebda4d472b0d 100644 --- a/core/java/android/view/flags/scroll_feedback_flags.aconfig +++ b/core/java/android/view/flags/scroll_feedback_flags.aconfig @@ -28,5 +28,5 @@ flag { namespace: "wear_frameworks" name: "dynamic_view_rotary_haptics_configuration" description: "Whether ScrollFeedbackProvider dynamically disables View-based rotary haptics." - bug: "377998870 " + bug: "377998870" } diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index a5603399142b..afe195c48b01 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -523,7 +523,6 @@ public class EditorInfo implements InputType, Parcelable { @Nullable public LocaleList hintLocales = null; - /** * List of acceptable MIME types for * {@link InputConnection#commitContent(InputContentInfo, int, Bundle)}. @@ -758,6 +757,30 @@ public class EditorInfo implements InputType, Parcelable { return mIsStylusHandwritingEnabled; } + private boolean mWritingToolsEnabled = true; + + /** + * Returns {@code true} when an {@code Editor} has writing tools enabled. + * {@code true} by default for all editors. Toolkits can optionally disable them where not + * relevant e.g. passwords, number input, etc. + * @see #setWritingToolsEnabled(boolean) + */ + @FlaggedApi(Flags.FLAG_WRITING_TOOLS) + public boolean isWritingToolsEnabled() { + return mWritingToolsEnabled; + } + + /** + * Set {@code false} if {@code Editor} opts-out of writing tools, that enable IMEs to replace + * text with generative AI text. + * @param enabled set {@code true} to enabled or {@code false to disable} support. + * @see #isWritingToolsEnabled() + */ + @FlaggedApi(Flags.FLAG_WRITING_TOOLS) + public void setWritingToolsEnabled(boolean enabled) { + mWritingToolsEnabled = enabled; + } + /** * If not {@code null}, this editor needs to talk to IMEs that run for the specified user, no * matter what user ID the calling process has. @@ -1276,6 +1299,7 @@ public class EditorInfo implements InputType, Parcelable { + InputMethodDebug.handwritingGestureTypeFlagsToString( mSupportedHandwritingGesturePreviewTypes)); pw.println(prefix + "isStylusHandwritingEnabled=" + mIsStylusHandwritingEnabled); + pw.println(prefix + "writingToolsEnabled=" + mWritingToolsEnabled); pw.println(prefix + "contentMimeTypes=" + Arrays.toString(contentMimeTypes)); if (targetInputMethodUser != null) { pw.println(prefix + "targetInputMethodUserId=" + targetInputMethodUser.getIdentifier()); @@ -1356,6 +1380,7 @@ public class EditorInfo implements InputType, Parcelable { } dest.writeStringArray(contentMimeTypes); UserHandle.writeToParcel(targetInputMethodUser, dest); + dest.writeBoolean(mWritingToolsEnabled); } /** @@ -1396,6 +1421,7 @@ public class EditorInfo implements InputType, Parcelable { res.hintLocales = hintLocales.isEmpty() ? null : hintLocales; res.contentMimeTypes = source.readStringArray(); res.targetInputMethodUser = UserHandle.readFromParcel(source); + res.mWritingToolsEnabled = source.readBoolean(); return res; } diff --git a/core/java/android/view/inputmethod/flags.aconfig b/core/java/android/view/inputmethod/flags.aconfig index e619ab064005..deaf95797127 100644 --- a/core/java/android/view/inputmethod/flags.aconfig +++ b/core/java/android/view/inputmethod/flags.aconfig @@ -175,3 +175,12 @@ flag { bug: "342672560" is_fixed_read_only: true } + +flag { + name: "adaptive_handwriting_bounds" + is_exported: true + namespace: "input_method" + description: "Feature flag for adaptively increasing handwriting bounds." + bug: "350047836" + is_fixed_read_only: true +} diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index d7750bd412a3..cb70466fcd81 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -106,6 +106,7 @@ import android.os.Parcelable; import android.os.ParcelableParcel; import android.os.Process; import android.os.SystemClock; +import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.text.BoringLayout; @@ -9229,174 +9230,179 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override protected void onDraw(Canvas canvas) { - restartMarqueeIfNeeded(); + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "TextView.onDraw"); + try { + restartMarqueeIfNeeded(); - // Draw the background for this view - super.onDraw(canvas); - - final int compoundPaddingLeft = getCompoundPaddingLeft(); - final int compoundPaddingTop = getCompoundPaddingTop(); - final int compoundPaddingRight = getCompoundPaddingRight(); - final int compoundPaddingBottom = getCompoundPaddingBottom(); - final int scrollX = mScrollX; - final int scrollY = mScrollY; - final int right = mRight; - final int left = mLeft; - final int bottom = mBottom; - final int top = mTop; - final boolean isLayoutRtl = isLayoutRtl(); - final int offset = getHorizontalOffsetForDrawables(); - final int leftOffset = isLayoutRtl ? 0 : offset; - final int rightOffset = isLayoutRtl ? offset : 0; + // Draw the background for this view + super.onDraw(canvas); - final Drawables dr = mDrawables; - if (dr != null) { - /* - * Compound, not extended, because the icon is not clipped - * if the text height is smaller. - */ + final int compoundPaddingLeft = getCompoundPaddingLeft(); + final int compoundPaddingTop = getCompoundPaddingTop(); + final int compoundPaddingRight = getCompoundPaddingRight(); + final int compoundPaddingBottom = getCompoundPaddingBottom(); + final int scrollX = mScrollX; + final int scrollY = mScrollY; + final int right = mRight; + final int left = mLeft; + final int bottom = mBottom; + final int top = mTop; + final boolean isLayoutRtl = isLayoutRtl(); + final int offset = getHorizontalOffsetForDrawables(); + final int leftOffset = isLayoutRtl ? 0 : offset; + final int rightOffset = isLayoutRtl ? offset : 0; - int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop; - int hspace = right - left - compoundPaddingRight - compoundPaddingLeft; + final Drawables dr = mDrawables; + if (dr != null) { + /* + * Compound, not extended, because the icon is not clipped + * if the text height is smaller. + */ - // IMPORTANT: The coordinates computed are also used in invalidateDrawable() - // Make sure to update invalidateDrawable() when changing this code. - if (dr.mShowing[Drawables.LEFT] != null) { - canvas.save(); - canvas.translate(scrollX + mPaddingLeft + leftOffset, - scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightLeft) / 2); - dr.mShowing[Drawables.LEFT].draw(canvas); - canvas.restore(); - } + int vspace = bottom - top - compoundPaddingBottom - compoundPaddingTop; + int hspace = right - left - compoundPaddingRight - compoundPaddingLeft; + + // IMPORTANT: The coordinates computed are also used in invalidateDrawable() + // Make sure to update invalidateDrawable() when changing this code. + if (dr.mShowing[Drawables.LEFT] != null) { + canvas.save(); + canvas.translate(scrollX + mPaddingLeft + leftOffset, + scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightLeft) / 2); + dr.mShowing[Drawables.LEFT].draw(canvas); + canvas.restore(); + } - // IMPORTANT: The coordinates computed are also used in invalidateDrawable() - // Make sure to update invalidateDrawable() when changing this code. - if (dr.mShowing[Drawables.RIGHT] != null) { - canvas.save(); - canvas.translate(scrollX + right - left - mPaddingRight - - dr.mDrawableSizeRight - rightOffset, - scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2); - dr.mShowing[Drawables.RIGHT].draw(canvas); - canvas.restore(); - } + // IMPORTANT: The coordinates computed are also used in invalidateDrawable() + // Make sure to update invalidateDrawable() when changing this code. + if (dr.mShowing[Drawables.RIGHT] != null) { + canvas.save(); + canvas.translate(scrollX + right - left - mPaddingRight + - dr.mDrawableSizeRight - rightOffset, + scrollY + compoundPaddingTop + (vspace - dr.mDrawableHeightRight) / 2); + dr.mShowing[Drawables.RIGHT].draw(canvas); + canvas.restore(); + } - // IMPORTANT: The coordinates computed are also used in invalidateDrawable() - // Make sure to update invalidateDrawable() when changing this code. - if (dr.mShowing[Drawables.TOP] != null) { - canvas.save(); - canvas.translate(scrollX + compoundPaddingLeft - + (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop); - dr.mShowing[Drawables.TOP].draw(canvas); - canvas.restore(); - } + // IMPORTANT: The coordinates computed are also used in invalidateDrawable() + // Make sure to update invalidateDrawable() when changing this code. + if (dr.mShowing[Drawables.TOP] != null) { + canvas.save(); + canvas.translate(scrollX + compoundPaddingLeft + + (hspace - dr.mDrawableWidthTop) / 2, scrollY + mPaddingTop); + dr.mShowing[Drawables.TOP].draw(canvas); + canvas.restore(); + } - // IMPORTANT: The coordinates computed are also used in invalidateDrawable() - // Make sure to update invalidateDrawable() when changing this code. - if (dr.mShowing[Drawables.BOTTOM] != null) { - canvas.save(); - canvas.translate(scrollX + compoundPaddingLeft - + (hspace - dr.mDrawableWidthBottom) / 2, - scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom); - dr.mShowing[Drawables.BOTTOM].draw(canvas); - canvas.restore(); + // IMPORTANT: The coordinates computed are also used in invalidateDrawable() + // Make sure to update invalidateDrawable() when changing this code. + if (dr.mShowing[Drawables.BOTTOM] != null) { + canvas.save(); + canvas.translate(scrollX + compoundPaddingLeft + + (hspace - dr.mDrawableWidthBottom) / 2, + scrollY + bottom - top - mPaddingBottom - dr.mDrawableSizeBottom); + dr.mShowing[Drawables.BOTTOM].draw(canvas); + canvas.restore(); + } } - } - int color = mCurTextColor; + int color = mCurTextColor; - if (mLayout == null) { - assumeLayout(); - } + if (mLayout == null) { + assumeLayout(); + } + + Layout layout = mLayout; - Layout layout = mLayout; + if (mHint != null && !mHideHint && mText.length() == 0) { + if (mHintTextColor != null) { + color = mCurHintTextColor; + } - if (mHint != null && !mHideHint && mText.length() == 0) { - if (mHintTextColor != null) { - color = mCurHintTextColor; + layout = mHintLayout; } - layout = mHintLayout; - } + mTextPaint.setColor(color); + mTextPaint.drawableState = getDrawableState(); - mTextPaint.setColor(color); - mTextPaint.drawableState = getDrawableState(); + canvas.save(); + /* Would be faster if we didn't have to do this. Can we chop the + (displayable) text so that we don't need to do this ever? + */ - canvas.save(); - /* Would be faster if we didn't have to do this. Can we chop the - (displayable) text so that we don't need to do this ever? - */ + int extendedPaddingTop = getExtendedPaddingTop(); + int extendedPaddingBottom = getExtendedPaddingBottom(); - int extendedPaddingTop = getExtendedPaddingTop(); - int extendedPaddingBottom = getExtendedPaddingBottom(); + final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop; + final int maxScrollY = mLayout.getHeight() - vspace; - final int vspace = mBottom - mTop - compoundPaddingBottom - compoundPaddingTop; - final int maxScrollY = mLayout.getHeight() - vspace; + float clipLeft = compoundPaddingLeft + scrollX; + float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY; + float clipRight = right - left - getCompoundPaddingRight() + scrollX; + float clipBottom = bottom - top + scrollY + - ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom); - float clipLeft = compoundPaddingLeft + scrollX; - float clipTop = (scrollY == 0) ? 0 : extendedPaddingTop + scrollY; - float clipRight = right - left - getCompoundPaddingRight() + scrollX; - float clipBottom = bottom - top + scrollY - - ((scrollY == maxScrollY) ? 0 : extendedPaddingBottom); + if (mShadowRadius != 0) { + clipLeft += Math.min(0, mShadowDx - mShadowRadius); + clipRight += Math.max(0, mShadowDx + mShadowRadius); - if (mShadowRadius != 0) { - clipLeft += Math.min(0, mShadowDx - mShadowRadius); - clipRight += Math.max(0, mShadowDx + mShadowRadius); + clipTop += Math.min(0, mShadowDy - mShadowRadius); + clipBottom += Math.max(0, mShadowDy + mShadowRadius); + } - clipTop += Math.min(0, mShadowDy - mShadowRadius); - clipBottom += Math.max(0, mShadowDy + mShadowRadius); - } + canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom); - canvas.clipRect(clipLeft, clipTop, clipRight, clipBottom); + int voffsetText = 0; + int voffsetCursor = 0; - int voffsetText = 0; - int voffsetCursor = 0; + // translate in by our padding + /* shortcircuit calling getVerticaOffset() */ + if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) { + voffsetText = getVerticalOffset(false); + voffsetCursor = getVerticalOffset(true); + } + canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText); + + final int layoutDirection = getLayoutDirection(); + final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); + if (isMarqueeFadeEnabled()) { + if (!mSingleLine && getLineCount() == 1 && canMarquee() + && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) { + final int width = mRight - mLeft; + final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight(); + final float dx = mLayout.getLineRight(0) - (width - padding); + canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f); + } - // translate in by our padding - /* shortcircuit calling getVerticaOffset() */ - if ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) != Gravity.TOP) { - voffsetText = getVerticalOffset(false); - voffsetCursor = getVerticalOffset(true); - } - canvas.translate(compoundPaddingLeft, extendedPaddingTop + voffsetText); - - final int layoutDirection = getLayoutDirection(); - final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection); - if (isMarqueeFadeEnabled()) { - if (!mSingleLine && getLineCount() == 1 && canMarquee() - && (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) { - final int width = mRight - mLeft; - final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight(); - final float dx = mLayout.getLineRight(0) - (width - padding); - canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f); + if (mMarquee != null && mMarquee.isRunning()) { + final float dx = -mMarquee.getScroll(); + canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f); + } } - if (mMarquee != null && mMarquee.isRunning()) { - final float dx = -mMarquee.getScroll(); - canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f); - } - } + final int cursorOffsetVertical = voffsetCursor - voffsetText; - final int cursorOffsetVertical = voffsetCursor - voffsetText; + maybeUpdateHighlightPaths(); + // If there is a gesture preview highlight, then the selection or cursor is not drawn. + Path highlight = hasGesturePreviewHighlight() ? null : getUpdatedHighlightPath(); + if (mEditor != null) { + mEditor.onDraw(canvas, layout, mHighlightPaths, mHighlightPaints, highlight, + mHighlightPaint, cursorOffsetVertical); + } else { + layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint, + cursorOffsetVertical); + } - maybeUpdateHighlightPaths(); - // If there is a gesture preview highlight, then the selection or cursor is not drawn. - Path highlight = hasGesturePreviewHighlight() ? null : getUpdatedHighlightPath(); - if (mEditor != null) { - mEditor.onDraw(canvas, layout, mHighlightPaths, mHighlightPaints, highlight, - mHighlightPaint, cursorOffsetVertical); - } else { - layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint, - cursorOffsetVertical); - } + if (mMarquee != null && mMarquee.shouldDrawGhost()) { + final float dx = mMarquee.getGhostOffset(); + canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f); + layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint, + cursorOffsetVertical); + } - if (mMarquee != null && mMarquee.shouldDrawGhost()) { - final float dx = mMarquee.getGhostOffset(); - canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f); - layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint, - cursorOffsetVertical); + canvas.restore(); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); } - - canvas.restore(); } @Override @@ -11254,192 +11260,201 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int widthMode = MeasureSpec.getMode(widthMeasureSpec); - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - int widthSize = MeasureSpec.getSize(widthMeasureSpec); - int heightSize = MeasureSpec.getSize(heightMeasureSpec); - - int width; - int height; + Trace.traceBegin(Trace.TRACE_TAG_VIEW, "TextView.onMeasure"); + try { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); - BoringLayout.Metrics boring = UNKNOWN_BORING; - BoringLayout.Metrics hintBoring = UNKNOWN_BORING; + int width; + int height; - if (mTextDir == null) { - mTextDir = getTextDirectionHeuristic(); - } + BoringLayout.Metrics boring = UNKNOWN_BORING; + BoringLayout.Metrics hintBoring = UNKNOWN_BORING; - int des = -1; - boolean fromexisting = false; - final float widthLimit = (widthMode == MeasureSpec.AT_MOST) - ? (float) widthSize : Float.MAX_VALUE; - - if (widthMode == MeasureSpec.EXACTLY) { - // Parent has told us how big to be. So be it. - width = widthSize; - } else { - if (mLayout != null && mEllipsize == null) { - des = desired(mLayout, mUseBoundsForWidth); + if (mTextDir == null) { + mTextDir = getTextDirectionHeuristic(); } - if (des < 0) { - boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, - isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(), - mBoring); - if (boring != null) { - mBoring = boring; - } - } else { - fromexisting = true; - } + int des = -1; + boolean fromexisting = false; + final float widthLimit = (widthMode == MeasureSpec.AT_MOST) + ? (float) widthSize : Float.MAX_VALUE; - if (boring == null || boring == UNKNOWN_BORING) { - if (des < 0) { - des = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mTransformed, 0, - mTransformed.length(), mTextPaint, mTextDir, widthLimit, - mUseBoundsForWidth)); - } - width = des; + if (widthMode == MeasureSpec.EXACTLY) { + // Parent has told us how big to be. So be it. + width = widthSize; } else { - if (mUseBoundsForWidth) { - RectF bbox = boring.getDrawingBoundingBox(); - float rightMax = Math.max(bbox.right, boring.width); - float leftMin = Math.min(bbox.left, 0); - width = Math.max(boring.width, (int) Math.ceil(rightMax - leftMin)); - } else { - width = boring.width; + if (mLayout != null && mEllipsize == null) { + des = desired(mLayout, mUseBoundsForWidth); } - } - - final Drawables dr = mDrawables; - if (dr != null) { - width = Math.max(width, dr.mDrawableWidthTop); - width = Math.max(width, dr.mDrawableWidthBottom); - } - - if (mHint != null) { - int hintDes = -1; - int hintWidth; - if (mHintLayout != null && mEllipsize == null) { - hintDes = desired(mHintLayout, mUseBoundsForWidth); - } - - if (hintDes < 0) { - hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir, + if (des < 0) { + boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(), - mHintBoring); - if (hintBoring != null) { - mHintBoring = hintBoring; + mBoring); + if (boring != null) { + mBoring = boring; } + } else { + fromexisting = true; } - if (hintBoring == null || hintBoring == UNKNOWN_BORING) { - if (hintDes < 0) { - hintDes = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mHint, 0, - mHint.length(), mTextPaint, mTextDir, widthLimit, + if (boring == null || boring == UNKNOWN_BORING) { + if (des < 0) { + des = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mTransformed, 0, + mTransformed.length(), mTextPaint, mTextDir, widthLimit, mUseBoundsForWidth)); } - hintWidth = hintDes; + width = des; } else { - hintWidth = hintBoring.width; + if (mUseBoundsForWidth) { + RectF bbox = boring.getDrawingBoundingBox(); + float rightMax = Math.max(bbox.right, boring.width); + float leftMin = Math.min(bbox.left, 0); + width = Math.max(boring.width, (int) Math.ceil(rightMax - leftMin)); + } else { + width = boring.width; + } } - if (hintWidth > width) { - width = hintWidth; + final Drawables dr = mDrawables; + if (dr != null) { + width = Math.max(width, dr.mDrawableWidthTop); + width = Math.max(width, dr.mDrawableWidthBottom); } - } - width += getCompoundPaddingLeft() + getCompoundPaddingRight(); + if (mHint != null) { + int hintDes = -1; + int hintWidth; - if (mMaxWidthMode == EMS) { - width = Math.min(width, mMaxWidth * getLineHeight()); - } else { - width = Math.min(width, mMaxWidth); - } + if (mHintLayout != null && mEllipsize == null) { + hintDes = desired(mHintLayout, mUseBoundsForWidth); + } - if (mMinWidthMode == EMS) { - width = Math.max(width, mMinWidth * getLineHeight()); - } else { - width = Math.max(width, mMinWidth); - } + if (hintDes < 0) { + hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir, + isFallbackLineSpacingForBoringLayout(), + getResolvedMinimumFontMetrics(), + mHintBoring); + if (hintBoring != null) { + mHintBoring = hintBoring; + } + } - // Check against our minimum width - width = Math.max(width, getSuggestedMinimumWidth()); + if (hintBoring == null || hintBoring == UNKNOWN_BORING) { + if (hintDes < 0) { + hintDes = (int) Math.ceil(Layout.getDesiredWidthWithLimit(mHint, 0, + mHint.length(), mTextPaint, mTextDir, widthLimit, + mUseBoundsForWidth)); + } + hintWidth = hintDes; + } else { + hintWidth = hintBoring.width; + } - if (widthMode == MeasureSpec.AT_MOST) { - width = Math.min(widthSize, width); - } - } + if (hintWidth > width) { + width = hintWidth; + } + } - int want = width - getCompoundPaddingLeft() - getCompoundPaddingRight(); - int unpaddedWidth = want; + width += getCompoundPaddingLeft() + getCompoundPaddingRight(); - if (mHorizontallyScrolling) want = VERY_WIDE; + if (mMaxWidthMode == EMS) { + width = Math.min(width, mMaxWidth * getLineHeight()); + } else { + width = Math.min(width, mMaxWidth); + } - int hintWant = want; - int hintWidth = (mHintLayout == null) ? hintWant : mHintLayout.getWidth(); + if (mMinWidthMode == EMS) { + width = Math.max(width, mMinWidth * getLineHeight()); + } else { + width = Math.max(width, mMinWidth); + } - if (mLayout == null) { - makeNewLayout(want, hintWant, boring, hintBoring, - width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false); - } else { - final boolean layoutChanged = (mLayout.getWidth() != want) || (hintWidth != hintWant) - || (mLayout.getEllipsizedWidth() - != width - getCompoundPaddingLeft() - getCompoundPaddingRight()); + // Check against our minimum width + width = Math.max(width, getSuggestedMinimumWidth()); + + if (widthMode == MeasureSpec.AT_MOST) { + width = Math.min(widthSize, width); + } + } - final boolean widthChanged = (mHint == null) && (mEllipsize == null) - && (want > mLayout.getWidth()) - && (mLayout instanceof BoringLayout - || (fromexisting && des >= 0 && des <= want)); + int want = width - getCompoundPaddingLeft() - getCompoundPaddingRight(); + int unpaddedWidth = want; - final boolean maximumChanged = (mMaxMode != mOldMaxMode) || (mMaximum != mOldMaximum); + if (mHorizontallyScrolling) want = VERY_WIDE; - if (layoutChanged || maximumChanged) { - if (!maximumChanged && widthChanged) { - mLayout.increaseWidthTo(want); + int hintWant = want; + int hintWidth = (mHintLayout == null) ? hintWant : mHintLayout.getWidth(); + + if (mLayout == null) { + makeNewLayout(want, hintWant, boring, hintBoring, + width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false); + } else { + final boolean layoutChanged = + (mLayout.getWidth() != want) || (hintWidth != hintWant) + || (mLayout.getEllipsizedWidth() + != width - getCompoundPaddingLeft() - getCompoundPaddingRight()); + + final boolean widthChanged = (mHint == null) && (mEllipsize == null) + && (want > mLayout.getWidth()) + && (mLayout instanceof BoringLayout + || (fromexisting && des >= 0 && des <= want)); + + final boolean maximumChanged = + (mMaxMode != mOldMaxMode) || (mMaximum != mOldMaximum); + + if (layoutChanged || maximumChanged) { + if (!maximumChanged && widthChanged) { + mLayout.increaseWidthTo(want); + } else { + makeNewLayout(want, hintWant, boring, hintBoring, + width - getCompoundPaddingLeft() - getCompoundPaddingRight(), + false); + } } else { - makeNewLayout(want, hintWant, boring, hintBoring, - width - getCompoundPaddingLeft() - getCompoundPaddingRight(), false); + // Nothing has changed } - } else { - // Nothing has changed } - } - if (heightMode == MeasureSpec.EXACTLY) { - // Parent has told us how big to be. So be it. - height = heightSize; - mDesiredHeightAtMeasure = -1; - } else { - int desired = getDesiredHeight(); + if (heightMode == MeasureSpec.EXACTLY) { + // Parent has told us how big to be. So be it. + height = heightSize; + mDesiredHeightAtMeasure = -1; + } else { + int desired = getDesiredHeight(); - height = desired; - mDesiredHeightAtMeasure = desired; + height = desired; + mDesiredHeightAtMeasure = desired; - if (heightMode == MeasureSpec.AT_MOST) { - height = Math.min(desired, heightSize); + if (heightMode == MeasureSpec.AT_MOST) { + height = Math.min(desired, heightSize); + } } - } - int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom(); - if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) { - unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum)); - } + int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom(); + if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) { + unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum)); + } - /* - * We didn't let makeNewLayout() register to bring the cursor into view, - * so do it here if there is any possibility that it is needed. - */ - if (mMovement != null - || mLayout.getWidth() > unpaddedWidth - || mLayout.getHeight() > unpaddedHeight) { - registerForPreDraw(); - } else { - scrollTo(0, 0); - } + /* + * We didn't let makeNewLayout() register to bring the cursor into view, + * so do it here if there is any possibility that it is needed. + */ + if (mMovement != null + || mLayout.getWidth() > unpaddedWidth + || mLayout.getHeight() > unpaddedHeight) { + registerForPreDraw(); + } else { + scrollTo(0, 0); + } - setMeasuredDimension(width, height); + setMeasuredDimension(width, height); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_VIEW); + } } /** diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java index 0f2dd10d7f47..2c21417fb790 100644 --- a/core/java/android/window/TransitionInfo.java +++ b/core/java/android/window/TransitionInfo.java @@ -49,6 +49,7 @@ import android.content.ComponentName; import android.graphics.Point; import android.graphics.Rect; import android.hardware.HardwareBuffer; +import android.os.BinderProxy; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; @@ -1089,8 +1090,13 @@ public final class TransitionInfo implements Parcelable { @Override public String toString() { final StringBuilder sb = new StringBuilder(); - sb.append('{'); sb.append(mContainer); - sb.append(" m="); sb.append(modeToString(mMode)); + sb.append('{'); + if (mContainer != null && !(mContainer.asBinder() instanceof BinderProxy)) { + // Only log the token if it is not a binder proxy and has additional container info + sb.append(mContainer); + sb.append(" "); + } + sb.append("m="); sb.append(modeToString(mMode)); sb.append(" f="); sb.append(flagsToString(mFlags)); if (mParent != null) { sb.append(" p="); sb.append(mParent); diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 3fe63ab17248..a88a17283482 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -1120,8 +1120,8 @@ public final class WindowContainerTransaction implements Parcelable { @NonNull public String toString() { return "WindowContainerTransaction {" - + " changes = " + mChanges - + " hops = " + mHierarchyOps + + " changes= " + mChanges + + " hops= " + mHierarchyOps + " errorCallbackToken=" + mErrorCallbackToken + " taskFragmentOrganizer=" + mTaskFragmentOrganizer + " }"; diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig index f474b34ac390..eebdeadcdeb2 100644 --- a/core/java/android/window/flags/lse_desktop_experience.aconfig +++ b/core/java/android/window/flags/lse_desktop_experience.aconfig @@ -402,4 +402,11 @@ flag { namespace: "lse_desktop_experience" description: "Enables HSUM on desktop mode." bug: "366397912" +} + +flag { + name: "enable_multiple_desktops" + namespace: "lse_desktop_experience" + description: "Enable multiple desktop sessions for desktop windowing." + bug: "379158791" }
\ No newline at end of file diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig index 4f924a82c9cc..ff69610dbf0e 100644 --- a/core/java/android/window/flags/windowing_frontend.aconfig +++ b/core/java/android/window/flags/windowing_frontend.aconfig @@ -418,6 +418,17 @@ flag { } flag { + name: "record_task_snapshots_before_shutdown" + namespace: "windowing_frontend" + description: "Record task snapshots before shutdown" + bug: "376821232" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { name: "predictive_back_three_button_nav" namespace: "systemui" description: "Enable Predictive Back Animation for 3-button-nav" diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl index 21c7baab4e83..469ab48385da 100644 --- a/core/java/com/android/internal/backup/IBackupTransport.aidl +++ b/core/java/com/android/internal/backup/IBackupTransport.aidl @@ -410,4 +410,15 @@ oneway interface IBackupTransport { * however backups initiated by the framework will call this method to retrieve one. */ void getBackupManagerMonitor(in AndroidFuture<IBackupManagerMonitor> resultFuture); + + /** + * Ask the transport whether packages that are about to be backed up or restored should not be + * put into a restricted mode by the framework and started normally instead. The + * {@code resultFuture} should be completed with a subset of the packages passed in, indicating + * which packages should NOT be put into restricted mode for the given operation type. + * + * @param operationType 0 for backup, 1 for restore. + */ + void getPackagesThatShouldNotUseRestrictedMode(in List<String> packageNames, int operationType, + in AndroidFuture<List<String>> resultFuture); } diff --git a/core/java/com/android/internal/policy/IDeviceLockedStateListener.aidl b/core/java/com/android/internal/policy/IDeviceLockedStateListener.aidl new file mode 100644 index 000000000000..cc626f699d43 --- /dev/null +++ b/core/java/com/android/internal/policy/IDeviceLockedStateListener.aidl @@ -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.internal.policy; + +oneway interface IDeviceLockedStateListener { + void onDeviceLockedStateChanged(boolean isDeviceLocked); +}
\ No newline at end of file diff --git a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java index a1c987f79304..eb682dff14de 100644 --- a/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/PerfettoProtoLogImpl.java @@ -676,15 +676,30 @@ public abstract class PerfettoProtoLogImpl extends IProtoLogClient.Stub implemen return internMap.get(string); } + protected boolean validateGroups(ILogger logger, String[] groups) { + for (int i = 0; i < groups.length; i++) { + String group = groups[i]; + IProtoLogGroup g = mLogGroups.get(group); + if (g == null) { + logger.log("No IProtoLogGroup named " + group); + return false; + } + } + return true; + } + private int setTextLogging(boolean value, ILogger logger, String... groups) { + if (!validateGroups(logger, groups)) { + return -1; + } + for (int i = 0; i < groups.length; i++) { String group = groups[i]; IProtoLogGroup g = mLogGroups.get(group); if (g != null) { g.setLogToLogcat(value); } else { - logger.log("No IProtoLogGroup named " + group); - return -1; + throw new RuntimeException("No IProtoLogGroup named " + group); } } diff --git a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java index 70d148a311f6..967a5ed1744d 100644 --- a/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java +++ b/core/java/com/android/internal/protolog/ProcessedPerfettoProtoLogImpl.java @@ -113,6 +113,10 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl { */ @Override public int startLoggingToLogcat(String[] groups, @NonNull ILogger logger) { + if (!validateGroups(logger, groups)) { + return -1; + } + mViewerConfigReader.loadViewerConfig(groups, logger); return super.startLoggingToLogcat(groups, logger); } @@ -125,8 +129,19 @@ public class ProcessedPerfettoProtoLogImpl extends PerfettoProtoLogImpl { */ @Override public int stopLoggingToLogcat(String[] groups, @NonNull ILogger logger) { + if (!validateGroups(logger, groups)) { + return -1; + } + + var status = super.stopLoggingToLogcat(groups, logger); + + if (status != 0) { + throw new RuntimeException("Failed to stop logging to logcat"); + } + + // If we successfully disabled logging, unload the viewer config. mViewerConfigReader.unloadViewerConfig(groups, logger); - return super.stopLoggingToLogcat(groups, logger); + return status; } @Deprecated diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java index 3303d875c427..8df3f2abcafd 100644 --- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java +++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java @@ -88,15 +88,19 @@ public final class RavenwoodEnvironment { /** @hide */ public static class CompatIdsForTest { // Enabled by default + /** Used for testing */ @ChangeId public static final long TEST_COMPAT_ID_1 = 368131859L; + /** Used for testing */ @Disabled @ChangeId public static final long TEST_COMPAT_ID_2 = 368131701L; + /** Used for testing */ @EnabledAfter(targetSdkVersion = S) @ChangeId public static final long TEST_COMPAT_ID_3 = 368131659L; + /** Used for testing */ @EnabledAfter(targetSdkVersion = UPSIDE_DOWN_CAKE) @ChangeId public static final long TEST_COMPAT_ID_4 = 368132057L; } diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl index 0e85e046e1b6..bf8a56508f54 100644 --- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -20,6 +20,7 @@ import android.telephony.BarringInfo; import android.telephony.CallState; import android.telephony.CellIdentity; import android.telephony.CellInfo; +import android.telephony.CellularIdentifierDisclosure; import android.telephony.DataConnectionRealTimeInfo; import android.telephony.LinkCapacityEstimate; import android.telephony.TelephonyDisplayInfo; @@ -28,6 +29,7 @@ import android.telephony.PhysicalChannelConfig; import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; import android.telephony.satellite.NtnSignalStrength; +import android.telephony.SecurityAlgorithmUpdate; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.emergency.EmergencyNumber; @@ -87,4 +89,6 @@ oneway interface IPhoneStateListener { void onCarrierRoamingNtnEligibleStateChanged(in boolean eligible); void onCarrierRoamingNtnAvailableServicesChanged(in int[] availableServices); void onCarrierRoamingNtnSignalStrengthChanged(in NtnSignalStrength ntnSignalStrength); + void onSecurityAlgorithmsChanged(in SecurityAlgorithmUpdate update); + void onCellularIdentifierDisclosedChanged(in CellularIdentifierDisclosure disclosure); } diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 0f268d5de62b..a296fbd1cfe4 100644 --- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -23,6 +23,7 @@ import android.telephony.BarringInfo; import android.telephony.CallQuality; import android.telephony.CellIdentity; import android.telephony.CellInfo; +import android.telephony.CellularIdentifierDisclosure; import android.telephony.LinkCapacityEstimate; import android.telephony.TelephonyDisplayInfo; import android.telephony.ims.ImsReasonInfo; @@ -30,6 +31,7 @@ import android.telephony.PhoneCapability; import android.telephony.PhysicalChannelConfig; import android.telephony.PreciseDataConnectionState; import android.telephony.satellite.NtnSignalStrength; +import android.telephony.SecurityAlgorithmUpdate; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.emergency.EmergencyNumber; @@ -132,4 +134,7 @@ interface ITelephonyRegistry { void removeSatelliteStateChangeListener(ISatelliteStateChangeListener listener, String pkg); void notifySatelliteStateChanged(boolean isEnabled); + void notifySecurityAlgorithmsChanged(int phoneId, int subId, in SecurityAlgorithmUpdate update); + void notifyCellularIdentifierDisclosedChanged( + int phoneId, int subId, in CellularIdentifierDisclosure disclosure); } diff --git a/core/java/com/android/internal/widget/NotificationProgressBar.java b/core/java/com/android/internal/widget/NotificationProgressBar.java index f2b36c3b9981..7a21275d611e 100644 --- a/core/java/com/android/internal/widget/NotificationProgressBar.java +++ b/core/java/com/android/internal/widget/NotificationProgressBar.java @@ -59,6 +59,8 @@ import java.util.TreeSet; public final class NotificationProgressBar extends ProgressBar { private static final String TAG = "NotificationProgressBar"; + private NotificationProgressDrawable mNotificationProgressDrawable; + private NotificationProgressModel mProgressModel; @Nullable @@ -94,6 +96,12 @@ public final class NotificationProgressBar extends ProgressBar { defStyleAttr, defStyleRes); + try { + mNotificationProgressDrawable = getNotificationProgressDrawable(); + } catch (IllegalStateException ex) { + Log.e(TAG, "Can't get NotificationProgressDrawable", ex); + } + // Supports setting the tracker in xml, but ProgressStyle notifications set/override it // via {@code setProgressTrackerIcon}. final Drawable tracker = a.getDrawable(R.styleable.NotificationProgressBar_tracker); @@ -131,11 +139,8 @@ public final class NotificationProgressBar extends ProgressBar { progressMax, mProgressModel.isStyledByProgress()); - try { - final NotificationProgressDrawable drawable = getNotificationProgressDrawable(); - drawable.setParts(mProgressDrawableParts); - } catch (IllegalStateException ex) { - Log.e(TAG, "Can't set parts because can't get NotificationProgressDrawable", ex); + if (mNotificationProgressDrawable != null) { + mNotificationProgressDrawable.setParts(mProgressDrawableParts); } setMax(progressMax); @@ -195,10 +200,6 @@ public final class NotificationProgressBar extends ProgressBar { } private void setTracker(@Nullable Drawable tracker) { - if (isIndeterminate() && tracker != null) { - return; - } - final boolean needUpdate = mTracker != null && tracker != mTracker; if (needUpdate) { mTracker.setCallback(null); @@ -222,6 +223,9 @@ public final class NotificationProgressBar extends ProgressBar { } mTracker = tracker; + if (mNotificationProgressDrawable != null) { + mNotificationProgressDrawable.setHasTrackerIcon(mTracker != null); + } configureTrackerBounds(); @@ -275,16 +279,6 @@ public final class NotificationProgressBar extends ProgressBar { } @Override - @RemotableViewMethod - public synchronized void setIndeterminate(boolean indeterminate) { - super.setIndeterminate(indeterminate); - - if (isIndeterminate()) { - setTracker(null); - } - } - - @Override protected boolean verifyDrawable(@NonNull Drawable who) { return who == mTracker || super.verifyDrawable(who); } @@ -421,6 +415,8 @@ public final class NotificationProgressBar extends ProgressBar { @Override protected synchronized void onDraw(Canvas canvas) { super.onDraw(canvas); + + if (isIndeterminate()) return; drawTracker(canvas); } diff --git a/core/java/com/android/internal/widget/NotificationProgressDrawable.java b/core/java/com/android/internal/widget/NotificationProgressDrawable.java index fb6937c94a3e..e95225eede99 100644 --- a/core/java/com/android/internal/widget/NotificationProgressDrawable.java +++ b/core/java/com/android/internal/widget/NotificationProgressDrawable.java @@ -23,7 +23,6 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; -import android.graphics.DashPathEffect; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; @@ -62,21 +61,15 @@ public final class NotificationProgressDrawable extends Drawable { private boolean mMutated; private final ArrayList<Part> mParts = new ArrayList<>(); + private boolean mHasTrackerIcon; private final RectF mSegRectF = new RectF(); private final Rect mPointRect = new Rect(); private final RectF mPointRectF = new RectF(); - private final Paint mStrokePaint = new Paint(); - private final Paint mDashedStrokePaint = new Paint(); private final Paint mFillPaint = new Paint(); { - mStrokePaint.setStyle(Paint.Style.STROKE); - mStrokePaint.setStrokeCap(Paint.Cap.ROUND); - - mDashedStrokePaint.setStyle(Paint.Style.STROKE); - mFillPaint.setStyle(Paint.Style.FILL); } @@ -87,49 +80,15 @@ public final class NotificationProgressDrawable extends Drawable { } /** - * <p>Set the stroke width and default color for the drawable.</p> - * <p>Note: changing this property will affect all instances of a drawable loaded from a - * resource. It is recommended to invoke - * {@link #mutate()} before changing this property.</p> - * - * @param width The width in pixels of the stroke - * @param color The color of the stroke - * @see #mutate() - * @see #setStroke(int, int, float, float) - */ - public void setStroke(int width, @ColorInt int color) { - setStroke(width, color, 0, 0); - } - - /** - * <p>Set the stroke width and default color for the drawable. This method can also be used - * to dash the stroke for the dashed segments.</p> - * <p>Note: changing this property will affect all instances of a drawable loaded from a - * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p> - * - * @param width The width in pixels of the stroke - * @param color The color of the stroke - * @param dashWidth The length in pixels of the dashes, set to 0 to disable dashes - * @param dashGap The gap in pixels between dashes - * @see #mutate() - * @see #setStroke(int, int) - */ - public void setStroke(int width, @ColorInt int color, float dashWidth, float dashGap) { - mState.setStroke(width, color, dashWidth, dashGap); - setStrokeInternal(width, dashWidth, dashGap); - } - - /** - * <p>Set the stroke default color for the drawable.</p> + * <p>Set the segment default color for the drawable.</p> * <p>Note: changing this property will affect all instances of a drawable loaded from a * resource. It is recommended to invoke {@link #mutate()} before changing this property.</p> * * @param color The color of the stroke * @see #mutate() - * @see #setStroke(int, int, float, float) */ - public void setStrokeDefaultColor(@ColorInt int color) { - mState.setStrokeColor(color); + public void setSegmentDefaultColor(@ColorInt int color) { + mState.setSegmentColor(color); } /** @@ -144,25 +103,14 @@ public final class NotificationProgressDrawable extends Drawable { mState.setPointRectColor(color); } - private void setStrokeInternal(int width, float dashWidth, float dashGap) { - mStrokePaint.setStrokeWidth(width); - - mDashedStrokePaint.setStrokeWidth(width); - DashPathEffect e = null; - if (dashWidth > 0) { - e = new DashPathEffect(new float[] { dashWidth, dashGap }, 0); - } - mDashedStrokePaint.setPathEffect(e); - - invalidateSelf(); - } - /** * Set the segments and points that constitute the drawable. */ public void setParts(List<Part> parts) { mParts.clear(); mParts.addAll(parts); + + invalidateSelf(); } /** @@ -172,6 +120,16 @@ public final class NotificationProgressDrawable extends Drawable { setParts(Arrays.asList(parts)); } + /** + * Set whether a tracker is drawn on top of this NotificationProgressDrawable. + */ + public void setHasTrackerIcon(boolean hasTrackerIcon) { + if (mHasTrackerIcon != hasTrackerIcon) { + mHasTrackerIcon = hasTrackerIcon; + invalidateSelf(); + } + } + @Override public void draw(@NonNull Canvas canvas) { final float pointRadius = @@ -181,6 +139,7 @@ public final class NotificationProgressDrawable extends Drawable { float x = (float) getBounds().left; final float centerY = (float) getBounds().centerY(); final float totalWidth = (float) getBounds().width(); + float segPointGap = mState.mSegPointGap; final int numParts = mParts.size(); for (int iPart = 0; iPart < numParts; iPart++) { @@ -188,15 +147,19 @@ public final class NotificationProgressDrawable extends Drawable { final Part prevPart = iPart == 0 ? null : mParts.get(iPart - 1); final Part nextPart = iPart + 1 == numParts ? null : mParts.get(iPart + 1); if (part instanceof Segment segment) { + // Update the segment-point gap to 2X upon seeing the first faded segment. + // (Assuming that all segments before are solid, and all segments after are faded.) + if (segment.mFaded) { + segPointGap = mState.mSegPointGap * 2; + } final float segWidth = segment.mFraction * totalWidth; // Advance the start position to account for a point immediately prior. - final float startOffset = getSegStartOffset(prevPart, pointRadius, - mState.mSegPointGap, x); + final float startOffset = getSegStartOffset(prevPart, pointRadius, segPointGap, x); final float start = x + startOffset; // Retract the end position to account for the padding and a point immediately // after. - final float endOffset = getSegEndOffset(nextPart, pointRadius, mState.mSegPointGap, - mState.mSegSegGap, x + segWidth, totalWidth); + final float endOffset = getSegEndOffset(segment, nextPart, pointRadius, segPointGap, + mState.mSegSegGap, x + segWidth, totalWidth, mHasTrackerIcon); final float end = x + segWidth - endOffset; // Advance the current position to account for the segment's fraction of the total @@ -206,35 +169,15 @@ public final class NotificationProgressDrawable extends Drawable { // No space left to draw the segment if (start > end) continue; - if (segment.mDashed) { - // No caps when the segment is dashed. - - mDashedStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor - : mState.mFadedStrokeColor); - canvas.drawLine(start, centerY, end, centerY, mDashedStrokePaint); - } else if (end - start < mState.mStrokeWidth) { - // Not enough segment length to draw the caps - - final float rad = (end - start) / 2F; - final float capWidth = mStrokePaint.getStrokeWidth() / 2F; - - mFillPaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor - : mState.mStrokeColor); - - mSegRectF.set(start, centerY - capWidth, end, centerY + capWidth); - canvas.drawRoundRect(mSegRectF, rad, rad, mFillPaint); - } else { - // Leave space for the rounded line cap which extends beyond start/end. - final float capWidth = mStrokePaint.getStrokeWidth() / 2F; + final float radiusY = segment.mFaded ? mState.mFadedSegmentHeight / 2F + : mState.mSegmentHeight / 2F; + final float cornerRadius = mState.mSegmentCornerRadius; - // Transparent is not allowed (and also is the default in the data), so use that - // as a sentinel to be replaced by default - mStrokePaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor - : mState.mStrokeColor); + mFillPaint.setColor(segment.mColor != Color.TRANSPARENT ? segment.mColor + : (segment.mFaded ? mState.mFadedSegmentColor : mState.mSegmentColor)); - canvas.drawLine(start + capWidth, centerY, end - capWidth, centerY, - mStrokePaint); - } + mSegRectF.set(start, centerY - radiusY, end, centerY + radiusY); + canvas.drawRoundRect(mSegRectF, cornerRadius, cornerRadius, mFillPaint); } else if (part instanceof Point point) { final float pointWidth = 2 * pointRadius; float start = x - pointRadius; @@ -275,10 +218,17 @@ public final class NotificationProgressDrawable extends Drawable { return pointOffset + pointRadius + segPointGap; } - private static float getSegEndOffset(Part nextPart, float pointRadius, float segPointGap, - float segSegGap, float endX, float totalWidth) { + private static float getSegEndOffset(Segment seg, Part nextPart, float pointRadius, + float segPointGap, + float segSegGap, float endX, float totalWidth, boolean hasTrackerIcon) { if (nextPart == null) return 0F; - if (!(nextPart instanceof Point)) return segSegGap; + if (nextPart instanceof Segment nextSeg) { + if (!seg.mFaded && nextSeg.mFaded) { + // @see Segment#mFaded + return hasTrackerIcon ? 0F : segSegGap * 4F; + } + return segSegGap; + } final float pointWidth = 2 * pointRadius; final float pointOffset = (endX + pointRadius > totalWidth && totalWidth > pointWidth) @@ -439,21 +389,17 @@ public final class NotificationProgressDrawable extends Drawable { // Extract the theme attributes, if any. state.mThemeAttrsSegments = a.extractThemeAttrs(); - final int width = a.getDimensionPixelSize( - R.styleable.NotificationProgressDrawableSegments_width, state.mStrokeWidth); - final float dashWidth = a.getDimension( - R.styleable.NotificationProgressDrawableSegments_dashWidth, state.mStrokeDashWidth); - + state.mSegmentHeight = a.getDimension( + R.styleable.NotificationProgressDrawableSegments_height, state.mSegmentHeight); + state.mFadedSegmentHeight = a.getDimension( + R.styleable.NotificationProgressDrawableSegments_fadedHeight, + state.mFadedSegmentHeight); + state.mSegmentCornerRadius = a.getDimension( + R.styleable.NotificationProgressDrawableSegments_cornerRadius, + state.mSegmentCornerRadius); final int color = a.getColor(R.styleable.NotificationProgressDrawableSegments_color, - state.mStrokeColor); - - if (dashWidth != 0.0f) { - final float dashGap = a.getDimension( - R.styleable.NotificationProgressDrawableSegments_dashGap, state.mStrokeDashGap); - setStroke(width, color, dashWidth, dashGap); - } else { - setStroke(width, color); - } + state.mSegmentColor); + setSegmentDefaultColor(color); } private void updatePointsFromTypedArray(TypedArray a) { @@ -532,11 +478,24 @@ public final class NotificationProgressDrawable extends Drawable { /** * A segment is a part of the progress bar with non-zero length. For example, it can * represent a portion in a navigation journey with certain traffic condition. + * */ public static final class Segment implements Part { private final float mFraction; @ColorInt private final int mColor; - private final boolean mDashed; + /** Whether the segment is faded or not. + * <p> + * <pre> + * When mFaded is set to true, a combination of the following is done to the segment: + * 1. The drawing color is mColor with opacity updated to 15%. + * 2. The segment-point gap is 2X the segment-point gap for non-faded segments. + * 3. The gap between faded and non-faded segments is: + * 4X the segment-segment gap, when there is no tracker icon + * 0, when there is tracker icon + * </pre> + * </p> + */ + private final boolean mFaded; public Segment(float fraction) { this(fraction, Color.TRANSPARENT); @@ -546,10 +505,10 @@ public final class NotificationProgressDrawable extends Drawable { this(fraction, color, false); } - public Segment(float fraction, @ColorInt int color, boolean dashed) { + public Segment(float fraction, @ColorInt int color, boolean faded) { mFraction = fraction; mColor = color; - mDashed = dashed; + mFaded = faded; } public float getFraction() { @@ -560,14 +519,14 @@ public final class NotificationProgressDrawable extends Drawable { return this.mColor; } - public boolean getDashed() { - return this.mDashed; + public boolean getFaded() { + return this.mFaded; } @Override public String toString() { - return "Segment(fraction=" + this.mFraction + ", color=" + this.mColor + ", dashed=" - + this.mDashed + ')'; + return "Segment(fraction=" + this.mFraction + ", color=" + this.mColor + ", faded=" + + this.mFaded + ')'; } // Needed for unit tests @@ -580,12 +539,12 @@ public final class NotificationProgressDrawable extends Drawable { Segment that = (Segment) other; if (Float.compare(this.mFraction, that.mFraction) != 0) return false; if (this.mColor != that.mColor) return false; - return this.mDashed == that.mDashed; + return this.mFaded == that.mFaded; } @Override public int hashCode() { - return Objects.hash(mFraction, mColor, mDashed); + return Objects.hash(mFraction, mColor, mFaded); } } @@ -675,11 +634,11 @@ public final class NotificationProgressDrawable extends Drawable { int mChangingConfigurations; float mSegSegGap = 0.0f; float mSegPointGap = 0.0f; - int mStrokeWidth = 0; - int mStrokeColor; - int mFadedStrokeColor; - float mStrokeDashWidth = 0.0f; - float mStrokeDashGap = 0.0f; + float mSegmentHeight; + float mFadedSegmentHeight; + float mSegmentCornerRadius; + int mSegmentColor; + int mFadedSegmentColor; float mPointRadius; float mPointRectInset; float mPointRectCornerRadius; @@ -699,11 +658,11 @@ public final class NotificationProgressDrawable extends Drawable { mChangingConfigurations = orig.mChangingConfigurations; mSegSegGap = orig.mSegSegGap; mSegPointGap = orig.mSegPointGap; - mStrokeWidth = orig.mStrokeWidth; - mStrokeColor = orig.mStrokeColor; - mFadedStrokeColor = orig.mFadedStrokeColor; - mStrokeDashWidth = orig.mStrokeDashWidth; - mStrokeDashGap = orig.mStrokeDashGap; + mSegmentHeight = orig.mSegmentHeight; + mFadedSegmentHeight = orig.mFadedSegmentHeight; + mSegmentCornerRadius = orig.mSegmentCornerRadius; + mSegmentColor = orig.mSegmentColor; + mFadedSegmentColor = orig.mFadedSegmentColor; mPointRadius = orig.mPointRadius; mPointRectInset = orig.mPointRectInset; mPointRectCornerRadius = orig.mPointRectCornerRadius; @@ -721,17 +680,17 @@ public final class NotificationProgressDrawable extends Drawable { } private void applyDensityScaling(int sourceDensity, int targetDensity) { - if (mStrokeWidth > 0) { - mStrokeWidth = scaleFromDensity( - mStrokeWidth, sourceDensity, targetDensity, true); + if (mSegmentHeight > 0) { + mSegmentHeight = scaleFromDensity( + mSegmentHeight, sourceDensity, targetDensity); } - if (mStrokeDashWidth > 0) { - mStrokeDashWidth = scaleFromDensity( - mStrokeDashWidth, sourceDensity, targetDensity); + if (mFadedSegmentHeight > 0) { + mFadedSegmentHeight = scaleFromDensity( + mFadedSegmentHeight, sourceDensity, targetDensity); } - if (mStrokeDashGap > 0) { - mStrokeDashGap = scaleFromDensity( - mStrokeDashGap, sourceDensity, targetDensity); + if (mSegmentCornerRadius > 0) { + mSegmentCornerRadius = scaleFromDensity( + mSegmentCornerRadius, sourceDensity, targetDensity); } if (mPointRadius > 0) { mPointRadius = scaleFromDensity( @@ -788,17 +747,9 @@ public final class NotificationProgressDrawable extends Drawable { } } - public void setStroke(int width, int color, float dashWidth, float dashGap) { - mStrokeWidth = width; - mStrokeDashWidth = dashWidth; - mStrokeDashGap = dashGap; - - setStrokeColor(color); - } - - public void setStrokeColor(int color) { - mStrokeColor = color; - mFadedStrokeColor = getFadedColor(color); + public void setSegmentColor(int color) { + mSegmentColor = color; + mFadedSegmentColor = getFadedColor(color); } public void setPointRectColor(int color) { @@ -808,11 +759,14 @@ public final class NotificationProgressDrawable extends Drawable { } /** - * Get a color with an opacity that's 50% of the input color. + * Get a color with an opacity that's 25% of the input color. */ @ColorInt static int getFadedColor(@ColorInt int color) { - return Color.argb(Color.alpha(color) / 2, Color.red(color), Color.green(color), + return Color.argb( + (int) (Color.alpha(color) * 0.25f + 0.5f), + Color.red(color), + Color.green(color), Color.blue(color)); } @@ -836,15 +790,6 @@ public final class NotificationProgressDrawable extends Drawable { } private void updateLocalState() { - final State state = mState; - - mStrokePaint.setStrokeWidth(state.mStrokeWidth); - mDashedStrokePaint.setStrokeWidth(state.mStrokeWidth); - - if (state.mStrokeDashWidth != 0.0f) { - final DashPathEffect e = new DashPathEffect( - new float[] { state.mStrokeDashWidth, state.mStrokeDashGap }, 0); - mDashedStrokePaint.setPathEffect(e); - } + // NO-OP } } diff --git a/core/java/com/android/internal/widget/NotificationRowIconView.java b/core/java/com/android/internal/widget/NotificationRowIconView.java index 5fc61b00e331..c96e979138dd 100644 --- a/core/java/com/android/internal/widget/NotificationRowIconView.java +++ b/core/java/com/android/internal/widget/NotificationRowIconView.java @@ -19,12 +19,7 @@ package com.android.internal.widget; import android.annotation.Nullable; import android.app.Flags; import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapShader; -import android.graphics.Canvas; -import android.graphics.Paint; import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.util.AttributeSet; @@ -41,7 +36,6 @@ import android.widget.RemoteViews; public class NotificationRowIconView extends CachingIconView { private NotificationIconProvider mIconProvider; - private boolean mApplyCircularCrop = false; private Drawable mAppIcon = null; // Padding, background and colors set on the view prior to being overridden when showing the app @@ -221,84 +215,6 @@ public class NotificationRowIconView extends CachingIconView { } } - @Nullable - @Override - Drawable loadSizeRestrictedIcon(@Nullable Icon icon) { - final Drawable original = super.loadSizeRestrictedIcon(icon); - final Drawable result; - if (mApplyCircularCrop) { - result = makeCircularDrawable(original); - } else { - result = original; - } - - return result; - } - - /** - * Enables circle crop that makes given image circular - */ - @RemotableViewMethod(asyncImpl = "setApplyCircularCropAsync") - public void setApplyCircularCrop(boolean applyCircularCrop) { - mApplyCircularCrop = applyCircularCrop; - } - - /** - * Async version of {@link NotificationRowIconView#setApplyCircularCrop} - */ - public Runnable setApplyCircularCropAsync(boolean applyCircularCrop) { - mApplyCircularCrop = applyCircularCrop; - return () -> { - }; - } - - @Nullable - private Drawable makeCircularDrawable(@Nullable Drawable original) { - if (original == null) { - return original; - } - - final Bitmap source = drawableToBitmap(original); - - int size = Math.min(source.getWidth(), source.getHeight()); - - Bitmap squared = Bitmap.createScaledBitmap(source, size, size, /* filter= */ false); - Bitmap result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); - - final Canvas canvas = new Canvas(result); - final Paint paint = new Paint(); - paint.setShader( - new BitmapShader(squared, BitmapShader.TileMode.CLAMP, - BitmapShader.TileMode.CLAMP)); - paint.setAntiAlias(true); - float radius = size / 2f; - canvas.drawCircle(radius, radius, radius, paint); - return new BitmapDrawable(getResources(), result); - } - - private static Bitmap drawableToBitmap(Drawable drawable) { - if (drawable instanceof BitmapDrawable bitmapDrawable) { - final Bitmap bitmap = bitmapDrawable.getBitmap(); - if (bitmap.getConfig() == Bitmap.Config.HARDWARE) { - return bitmap.copy(Bitmap.Config.ARGB_8888, false); - } else { - return bitmap; - } - } - - int width = drawable.getIntrinsicWidth(); - width = width > 0 ? width : 1; - int height = drawable.getIntrinsicHeight(); - height = height > 0 ? height : 1; - - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - - return bitmap; - } - /** * A provider that allows this view to verify whether it should use the app icon instead of the * icon provided to it via setImageIcon, as well as actually fetching the app icon. It should diff --git a/core/jni/android_hardware_OverlayProperties.cpp b/core/jni/android_hardware_OverlayProperties.cpp index bb4084e8f39e..f64dec8eb215 100644 --- a/core/jni/android_hardware_OverlayProperties.cpp +++ b/core/jni/android_hardware_OverlayProperties.cpp @@ -106,7 +106,7 @@ static jobjectArray android_hardware_OverlayProperties_getLutProperties(JNIEnv* jlong nativeObject) { gui::OverlayProperties* overlayProperties = reinterpret_cast<gui::OverlayProperties*>(nativeObject); - if (overlayProperties->lutProperties.has_value()) { + if (!overlayProperties || !overlayProperties->lutProperties) { return NULL; } auto& lutProperties = overlayProperties->lutProperties.value(); diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index f9d00edce3fa..5a183925e38e 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -584,14 +584,23 @@ static jboolean android_media_AudioRecord_setInputDevice( return lpRecorder->setInputDevice(device_id) == NO_ERROR; } -static jint android_media_AudioRecord_getRoutedDeviceId( - JNIEnv *env, jobject thiz) { - +static jintArray android_media_AudioRecord_getRoutedDeviceIds(JNIEnv *env, jobject thiz) { sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz); - if (lpRecorder == 0) { - return 0; + if (lpRecorder == NULL) { + return NULL; + } + DeviceIdVector deviceIds = lpRecorder->getRoutedDeviceIds(); + jintArray result; + result = env->NewIntArray(deviceIds.size()); + if (result == NULL) { + return NULL; + } + jint *values = env->GetIntArrayElements(result, 0); + for (unsigned int i = 0; i < deviceIds.size(); i++) { + values[i++] = static_cast<jint>(deviceIds[i]); } - return (jint)lpRecorder->getRoutedDeviceId(); + env->ReleaseIntArrayElements(result, values, 0); + return result; } // Enable and Disable Callback methods are synchronized on the Java side @@ -821,8 +830,7 @@ static const JNINativeMethod gMethods[] = { // name, signature, funcPtr {"native_start", "(II)I", (void *)android_media_AudioRecord_start}, {"native_stop", "()V", (void *)android_media_AudioRecord_stop}, - {"native_setup", - "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/os/Parcel;JII)I", + {"native_setup", "(Ljava/lang/Object;Ljava/lang/Object;[IIIII[ILandroid/os/Parcel;JII)I", (void *)android_media_AudioRecord_setup}, {"native_finalize", "()V", (void *)android_media_AudioRecord_finalize}, {"native_release", "()V", (void *)android_media_AudioRecord_release}, @@ -846,7 +854,7 @@ static const JNINativeMethod gMethods[] = { {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_AudioRecord_native_getMetrics}, {"native_setInputDevice", "(I)Z", (void *)android_media_AudioRecord_setInputDevice}, - {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioRecord_getRoutedDeviceId}, + {"native_getRoutedDeviceIds", "()[I", (void *)android_media_AudioRecord_getRoutedDeviceIds}, {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback}, {"native_disableDeviceCallback", "()V", diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 8eaa7aa99a2d..3d9a19e129a8 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -109,6 +109,7 @@ static struct { // Valid only if an AudioDevicePort jfieldID mType; jfieldID mAddress; + jfieldID mSpeakerLayoutChannelMask; // other fields unused by JNI } gAudioPortFields; @@ -1084,6 +1085,8 @@ static jint convertAudioPortConfigToNativeWithDevicePort(JNIEnv *env, strncpy(nAudioPortConfig->ext.device.address, nDeviceAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN - 1); env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress); + nAudioPortConfig->ext.device.speaker_layout_channel_mask = outChannelMaskToNative( + env->GetIntField(jAudioDevicePort, gAudioPortFields.mSpeakerLayoutChannelMask)); env->DeleteLocalRef(jDeviceAddress); env->DeleteLocalRef(jAudioDevicePort); return jStatus; @@ -1541,10 +1544,12 @@ static jint convertAudioPortFromNative(JNIEnv *env, ScopedLocalRef<jobject> *jAu .encapsulation_metadata_types)); ALOGV("convertAudioPortFromNative is a device %08x", nAudioPort->ext.device.type); ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(nAudioPort->ext.device.address)); + int speakerLayoutChannelMask = outChannelMaskFromNative( + nAudioPort->active_config.ext.device.speaker_layout_channel_mask); jAudioPort->reset(env->NewObject(gAudioDevicePortClass, gAudioDevicePortCstor, jHandle.get(), jDeviceName.get(), jAudioProfiles.get(), jGains.get(), nAudioPort->ext.device.type, jAddress.get(), - jEncapsulationModes.get(), + speakerLayoutChannelMask, jEncapsulationModes.get(), jEncapsulationMetadataTypes.get(), jAudioDescriptors.get())); } else if (nAudioPort->type == AUDIO_PORT_TYPE_MIX) { @@ -3705,14 +3710,15 @@ int register_android_media_AudioSystem(JNIEnv *env) gAudioDevicePortCstor = GetMethodIDOrDie(env, audioDevicePortClass, "<init>", "(Landroid/media/AudioHandle;Ljava/lang/String;Ljava/util/List;" - "[Landroid/media/AudioGain;ILjava/lang/String;[I[I" + "[Landroid/media/AudioGain;ILjava/lang/String;I[I[I" "Ljava/util/List;)V"); // When access AudioPort as AudioDevicePort gAudioPortFields.mType = GetFieldIDOrDie(env, audioDevicePortClass, "mType", "I"); gAudioPortFields.mAddress = GetFieldIDOrDie(env, audioDevicePortClass, "mAddress", "Ljava/lang/String;"); - + gAudioPortFields.mSpeakerLayoutChannelMask = + GetFieldIDOrDie(env, audioDevicePortClass, "mSpeakerLayoutChannelMask", "I"); jclass audioMixPortClass = FindClassOrDie(env, "android/media/AudioMixPort"); gAudioMixPortClass = MakeGlobalRefOrDie(env, audioMixPortClass); gAudioMixPortCstor = diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 1557f9ed47a5..5d4d1ce20e5d 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -1190,15 +1190,23 @@ static jboolean android_media_AudioTrack_setOutputDevice( } return lpTrack->setOutputDevice(device_id) == NO_ERROR; } - -static jint android_media_AudioTrack_getRoutedDeviceId( - JNIEnv *env, jobject thiz) { - +static jintArray android_media_AudioTrack_getRoutedDeviceIds(JNIEnv *env, jobject thiz) { sp<AudioTrack> lpTrack = getAudioTrack(env, thiz); if (lpTrack == NULL) { - return 0; + return NULL; + } + DeviceIdVector deviceIds = lpTrack->getRoutedDeviceIds(); + jintArray result; + result = env->NewIntArray(deviceIds.size()); + if (result == NULL) { + return NULL; + } + jint *values = env->GetIntArrayElements(result, 0); + for (unsigned int i = 0; i < deviceIds.size(); i++) { + values[i++] = static_cast<jint>(deviceIds[i]); } - return (jint)lpTrack->getRoutedDeviceId(); + env->ReleaseIntArrayElements(result, values, 0); + return result; } static void android_media_AudioTrack_enableDeviceCallback( @@ -1503,7 +1511,7 @@ static const JNINativeMethod gMethods[] = { (void *)android_media_AudioTrack_setAuxEffectSendLevel}, {"native_attachAuxEffect", "(I)I", (void *)android_media_AudioTrack_attachAuxEffect}, {"native_setOutputDevice", "(I)Z", (void *)android_media_AudioTrack_setOutputDevice}, - {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId}, + {"native_getRoutedDeviceIds", "()[I", (void *)android_media_AudioTrack_getRoutedDeviceIds}, {"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback}, {"native_disableDeviceCallback", "()V", diff --git a/core/jni/android_media_DeviceCallback.cpp b/core/jni/android_media_DeviceCallback.cpp index a1a035110caf..ccdf633c842a 100644 --- a/core/jni/android_media_DeviceCallback.cpp +++ b/core/jni/android_media_DeviceCallback.cpp @@ -61,21 +61,20 @@ JNIDeviceCallback::~JNIDeviceCallback() } void JNIDeviceCallback::onAudioDeviceUpdate(audio_io_handle_t audioIo, - audio_port_handle_t deviceId) -{ + const DeviceIdVector& deviceIds) { JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { return; } - ALOGV("%s audioIo %d deviceId %d", __FUNCTION__, audioIo, deviceId); - env->CallStaticVoidMethod(mClass, - mPostEventFromNative, - mObject, - AUDIO_NATIVE_EVENT_ROUTING_CHANGE, deviceId, 0, NULL); + ALOGV("%s audioIo %d deviceIds %s", __FUNCTION__, audioIo, toString(deviceIds).c_str()); + // Java should query the new device ids once it gets the event. + // TODO(b/378505346): Pass the deviceIds to Java to avoid race conditions. + env->CallStaticVoidMethod(mClass, mPostEventFromNative, mObject, + AUDIO_NATIVE_EVENT_ROUTING_CHANGE, 0 /*arg1*/, 0 /*arg2*/, + NULL /*obj*/); if (env->ExceptionCheck()) { ALOGW("An exception occurred while notifying an event."); env->ExceptionClear(); } } - diff --git a/core/jni/android_media_DeviceCallback.h b/core/jni/android_media_DeviceCallback.h index 7ae788eaf058..0c9ccc89ba1a 100644 --- a/core/jni/android_media_DeviceCallback.h +++ b/core/jni/android_media_DeviceCallback.h @@ -31,8 +31,7 @@ public: JNIDeviceCallback(JNIEnv* env, jobject thiz, jobject weak_thiz, jmethodID postEventFromNative); ~JNIDeviceCallback(); - virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo, - audio_port_handle_t deviceId); + virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo, const DeviceIdVector& deviceIds); private: void sendEvent(int event); diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp index 49191ee02ad6..7ef7829c6ba5 100644 --- a/core/jni/android_util_Process.cpp +++ b/core/jni/android_util_Process.cpp @@ -33,6 +33,7 @@ #include <algorithm> #include <array> +#include <cctype> #include <cstring> #include <limits> #include <memory> @@ -1008,6 +1009,8 @@ jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz, } } if ((mode&PROC_OUT_STRING) != 0 && di < NS) { + std::replace_if(buffer+start, buffer+end, + [](unsigned char c){ return !std::isprint(c); }, '?'); jstring str = env->NewStringUTF(buffer+start); env->SetObjectArrayElement(outStrings, di, str); } diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 82b463ec9091..593b982d4cf2 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -758,54 +758,64 @@ static void nativeSetLuts(JNIEnv* env, jclass clazz, jlong transactionObj, jlong auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl*>(nativeObject); - ScopedIntArrayRW joffsets(env, joffsetArray); - if (joffsets.get() == nullptr) { - jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from joffsetArray"); - return; - } - ScopedIntArrayRW jdimensions(env, jdimensionArray); - if (jdimensions.get() == nullptr) { - jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jdimensionArray"); - return; - } - ScopedIntArrayRW jsizes(env, jsizeArray); - if (jsizes.get() == nullptr) { - jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsizeArray"); - return; - } - ScopedIntArrayRW jsamplingKeys(env, jsamplingKeyArray); - if (jsamplingKeys.get() == nullptr) { - jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsamplingKeyArray"); - return; - } + std::vector<int32_t> offsets; + std::vector<int32_t> dimensions; + std::vector<int32_t> sizes; + std::vector<int32_t> samplingKeys; + int32_t fd = -1; + + if (jdimensionArray) { + jsize numLuts = env->GetArrayLength(jdimensionArray); + ScopedIntArrayRW joffsets(env, joffsetArray); + if (joffsets.get() == nullptr) { + jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from joffsetArray"); + return; + } + ScopedIntArrayRW jdimensions(env, jdimensionArray); + if (jdimensions.get() == nullptr) { + jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jdimensionArray"); + return; + } + ScopedIntArrayRW jsizes(env, jsizeArray); + if (jsizes.get() == nullptr) { + jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsizeArray"); + return; + } + ScopedIntArrayRW jsamplingKeys(env, jsamplingKeyArray); + if (jsamplingKeys.get() == nullptr) { + jniThrowRuntimeException(env, "Failed to get ScopedIntArrayRW from jsamplingKeyArray"); + return; + } - jsize numLuts = env->GetArrayLength(jdimensionArray); - std::vector<int32_t> offsets(joffsets.get(), joffsets.get() + numLuts); - std::vector<int32_t> dimensions(jdimensions.get(), jdimensions.get() + numLuts); - std::vector<int32_t> sizes(jsizes.get(), jsizes.get() + numLuts); - std::vector<int32_t> samplingKeys(jsamplingKeys.get(), jsamplingKeys.get() + numLuts); + if (numLuts > 0) { + offsets = std::vector<int32_t>(joffsets.get(), joffsets.get() + numLuts); + dimensions = std::vector<int32_t>(jdimensions.get(), jdimensions.get() + numLuts); + sizes = std::vector<int32_t>(jsizes.get(), jsizes.get() + numLuts); + samplingKeys = std::vector<int32_t>(jsamplingKeys.get(), jsamplingKeys.get() + numLuts); - ScopedFloatArrayRW jbuffers(env, jbufferArray); - if (jbuffers.get() == nullptr) { - jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRW from jbufferArray"); - return; - } + ScopedFloatArrayRW jbuffers(env, jbufferArray); + if (jbuffers.get() == nullptr) { + jniThrowRuntimeException(env, "Failed to get ScopedFloatArrayRW from jbufferArray"); + return; + } - // create the shared memory and copy jbuffers - size_t bufferSize = jbuffers.size() * sizeof(float); - int32_t fd = ashmem_create_region("lut_shread_mem", bufferSize); - if (fd < 0) { - jniThrowRuntimeException(env, "ashmem_create_region() failed"); - return; - } - void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (ptr == MAP_FAILED) { - jniThrowRuntimeException(env, "Failed to map the shared memory"); - return; + // create the shared memory and copy jbuffers + size_t bufferSize = jbuffers.size() * sizeof(float); + fd = ashmem_create_region("lut_shared_mem", bufferSize); + if (fd < 0) { + jniThrowRuntimeException(env, "ashmem_create_region() failed"); + return; + } + void* ptr = mmap(nullptr, bufferSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (ptr == MAP_FAILED) { + jniThrowRuntimeException(env, "Failed to map the shared memory"); + return; + } + memcpy(ptr, jbuffers.get(), bufferSize); + // unmap + munmap(ptr, bufferSize); + } } - memcpy(ptr, jbuffers.get(), bufferSize); - // unmap - munmap(ptr, bufferSize); transaction->setLuts(ctrl, base::unique_fd(fd), offsets, dimensions, sizes, samplingKeys); } @@ -1332,8 +1342,9 @@ static void nativeSetDisplaySize(JNIEnv* env, jclass clazz, } } -static jobject convertDeviceProductInfoToJavaObject( - JNIEnv* env, const std::optional<DeviceProductInfo>& info) { +static jobject convertDeviceProductInfoToJavaObject(JNIEnv* env, + const std::optional<DeviceProductInfo>& info, + bool isInternal) { using ModelYear = android::DeviceProductInfo::ModelYear; using ManufactureYear = android::DeviceProductInfo::ManufactureYear; using ManufactureWeekAndYear = android::DeviceProductInfo::ManufactureWeekAndYear; @@ -1368,7 +1379,8 @@ static jobject convertDeviceProductInfoToJavaObject( // Section 8.7 - Physical Address of HDMI Specification Version 1.3a using android::hardware::display::IDeviceProductInfoConstants; if (info->relativeAddress.size() != 4) { - connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN; + connectionToSinkType = isInternal ? IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN + : IDeviceProductInfoConstants::CONNECTION_TO_SINK_UNKNOWN; } else if (info->relativeAddress[0] == 0) { connectionToSinkType = IDeviceProductInfoConstants::CONNECTION_TO_SINK_BUILT_IN; } else if (info->relativeAddress[1] == 0) { @@ -1390,12 +1402,14 @@ static jobject nativeGetStaticDisplayInfo(JNIEnv* env, jclass clazz, jlong id) { jobject object = env->NewObject(gStaticDisplayInfoClassInfo.clazz, gStaticDisplayInfoClassInfo.ctor); - env->SetBooleanField(object, gStaticDisplayInfoClassInfo.isInternal, - info.connectionType == ui::DisplayConnectionType::Internal); + + const bool isInternal = info.connectionType == ui::DisplayConnectionType::Internal; + env->SetBooleanField(object, gStaticDisplayInfoClassInfo.isInternal, isInternal); env->SetFloatField(object, gStaticDisplayInfoClassInfo.density, info.density); env->SetBooleanField(object, gStaticDisplayInfoClassInfo.secure, info.secure); env->SetObjectField(object, gStaticDisplayInfoClassInfo.deviceProductInfo, - convertDeviceProductInfoToJavaObject(env, info.deviceProductInfo)); + convertDeviceProductInfoToJavaObject(env, info.deviceProductInfo, + isInternal)); env->SetIntField(object, gStaticDisplayInfoClassInfo.installOrientation, static_cast<uint32_t>(info.installOrientation)); return object; @@ -2187,29 +2201,9 @@ public: return false; } - // Compute the count of data items we'll actually forward to Java. - size_t count = 0; - if (mRemovedVsyncId <= 0) { - count = jankData.size(); - } else { - for (const gui::JankData& frame : jankData) { - if (frame.frameVsyncId <= mRemovedVsyncId) { - count++; - } - } - } - - if (count == 0) { - return false; - } - - jobjectArray jJankDataArray = env->NewObjectArray(count, gJankDataClassInfo.clazz, nullptr); - for (size_t i = 0, j = 0; i < jankData.size() && j < count; i++) { - // Filter any data for frames past our removal vsync. - if (mRemovedVsyncId > 0 && jankData[i].frameVsyncId > mRemovedVsyncId) { - continue; - } - + jobjectArray jJankDataArray = + env->NewObjectArray(jankData.size(), gJankDataClassInfo.clazz, nullptr); + for (size_t i = 0; i < jankData.size(); i++) { // The exposed constants in SurfaceControl are simplified, so we need to translate the // jank type we get from SF to what is exposed in Java. int sfJankType = jankData[i].jankType; @@ -2236,7 +2230,7 @@ public: jankData[i].frameVsyncId, javaJankType, jankData[i].frameIntervalNs, jankData[i].scheduledAppFrameTimeNs, jankData[i].actualAppFrameTimeNs); - env->SetObjectArrayElement(jJankDataArray, j++, jJankData); + env->SetObjectArrayElement(jJankDataArray, i, jJankData); env->DeleteLocalRef(jJankData); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 3e0c1200749e..7fcbf19d137f 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -914,13 +914,26 @@ android:featureFlag="android.provider.user_keys" /> <!-- Allows an application to set default account for new contacts. - <p> This permission is only granted to system applications fulfilling the Contacts app role. + <p>This permission is only granted to system applications fulfilling the Contacts app role. <p>Protection level: internal|role @SystemApi @hide --> <permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS" - android:protectionLevel="internal|role" /> + android:protectionLevel="internal|role" + android:featureFlag="!android.provider.new_default_account_api_enabled"/> + + <!-- Allows an application to set default account for new contacts. + <p>This permission is only granted to system applications fulfilling the Contacts app role + and the application with known signers. + <p>Protection level: internal|role|knownSigner + @SystemApi + @hide + --> + <permission android:name="android.permission.SET_DEFAULT_ACCOUNT_FOR_CONTACTS" + android:protectionLevel="internal|role|knownSigner" + android:knownCerts="@array/config_setContactsDefaultAccountKnownSigners" + android:featureFlag="android.provider.new_default_account_api_enabled"/> <!-- ====================================================================== --> <!-- Permissions for accessing user's calendar --> @@ -1080,6 +1093,52 @@ <permission android:name="android.permission.SATELLITE_COMMUNICATION" android:protectionLevel="role|signature|privileged" /> + <!-- ================================== --> + <!-- Permissions associated with picture and sound profiles --> + <!-- ================================== --> + <eat-comment /> + + <!-- @FlaggedApi(android.media.tv.flags.Flags.FLAG_APPLY_PICTURE_PROFILES) + Allows an app to apply a {@link MediaQualityManager.PictureProfile} to a layer via + {@link MediaCodec.PARAMETER_KEY_PICTURE_PROFILE} and, additionally, system apps via + {@link SurfaceControl.Transaction#setPictureProfileHandle}. + --> + <permission android:name="android.permission.APPLY_PICTURE_PROFILE" + android:protectionLevel="normal" + android:featureFlag="android.media.tv.flags.apply_picture_profiles"/> + + <!-- @hide + Allows MediaQualityService to observe any {@link MediaQualityManager.PictureProfile} + applied to any layer in the system by apps via + {@link MediaCodec.PARAMETER_KEY_PICTURE_PROFILE} and by system apps via + {@link SurfaceControl.Transaction#setPictureProfileHandle}. + --> + <permission android:name="android.permission.OBSERVE_PICTURE_PROFILES" + android:protectionLevel="signature|privileged" + android:featureFlag="android.media.tv.flags.apply_picture_profiles"/> + + <!-- + @SystemApi + @FlaggedApi("android.media.tv.flags.media_quality_fw") + Allows an application to access its picture profile from the media quality database. + <p> Protection level: signature|privileged|vendor privileged + @hide + --> + <permission android:name="android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE" + android:protectionLevel="signature|privileged|vendorPrivileged" + android:featureFlag="android.media.tv.flags.media_quality_fw"/> + + <!-- + @SystemApi + @FlaggedApi("android.media.tv.flags.media_quality_fw") + Allows an application to access its sound profile from the media quality database. + <p> Protection level: signature|privileged|vendor privileged + @hide + --> + <permission android:name="android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE" + android:protectionLevel="signature|privileged|vendorPrivileged" + android:featureFlag="android.media.tv.flags.media_quality_fw"/> + <!-- ====================================================================== --> <!-- Permissions for accessing external storage --> <!-- ====================================================================== --> @@ -4144,6 +4203,37 @@ <uses-permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE" android:featureFlag="android.security.aapm_api"/> + <!-- Allows an application to read the state of the ForensicService + @FlaggedApi(android.security.Flags.FLAG_AFL_API) + @SystemApi + @hide --> + <permission android:name="android.permission.READ_FORENSIC_STATE" + android:featureFlag="android.security.afl_api" + android:protectionLevel="signature|privileged" /> + <uses-permission android:name="android.permission.READ_FORENSIC_STATE" + android:featureFlag="android.security.afl_api"/> + + <!-- Allows an application to change the state of the ForensicService + @FlaggedApi(android.security.Flags.FLAG_AFL_API) + @SystemApi + @hide --> + <permission android:name="android.permission.MANAGE_FORENSIC_STATE" + android:featureFlag="android.security.afl_api" + android:protectionLevel="signature|privileged" /> + <uses-permission android:name="android.permission.MANAGE_FORENSIC_STATE" + android:featureFlag="android.security.afl_api"/> + + <!-- Must be required by any ForensicEventTransportService to ensure that + only the system can bind to it. + @FlaggedApi(android.security.Flags.FLAG_AFL_API) + @SystemApi + @hide --> + <permission android:name="android.permission.BIND_FORENSIC_EVENT_TRANSPORT_SERVICE" + android:featureFlag="android.security.afl_api" + android:protectionLevel="signature" /> + <uses-permission android:name="android.permission.BIND_FORENSIC_EVENT_TRANSPORT_SERVICE" + android:featureFlag="android.security.afl_api"/> + <!-- @SystemApi @hide Allows an application to set a device owner on retail demo devices.--> <permission android:name="android.permission.PROVISION_DEMO_DEVICE" android:protectionLevel="signature|setup|knownSigner" @@ -4991,16 +5081,16 @@ android:protectionLevel="signature|privileged|role" android:featureFlag="com.android.settingslib.flags.settings_catalyst" /> - <!-- @FlaggedApi(com.android.settingslib.flags.Flags.FLAG_SETTINGS_CATALYST) + <!-- @FlaggedApi(com.android.settingslib.flags.Flags.FLAG_WRITE_SYSTEM_PREFERENCE_PERMISSION_ENABLED) Allows an application to access the Settings Preference services to write settings values exposed by the system Settings app and system apps that contribute settings surfaced in the Settings app. <p>This allows the calling application to write settings values through the host application, agnostic of underlying storage. - <p>Protection Level: signature|privileged|appop - appop to be added in followup --> + <p>Protection Level: signature|privileged|appop --> <permission android:name="android.permission.WRITE_SYSTEM_PREFERENCES" - android:protectionLevel="signature|privileged" - android:featureFlag="com.android.settingslib.flags.settings_catalyst" /> + android:protectionLevel="signature|privileged|appop" + android:featureFlag="com.android.settingslib.flags.write_system_preference_permission_enabled" /> <!-- ========================================= --> <!-- Permissions for special development tools --> @@ -5497,7 +5587,8 @@ <permission android:name="android.permission.BIND_VISUAL_QUERY_DETECTION_SERVICE" android:protectionLevel="signature" /> - <!-- Allows an application to subscribe to keyguard locked (i.e., showing) state. + <!-- Allows an application to subscribe to device locked and keyguard locked (i.e., showing) + state. <p>Protection level: signature|role <p>Intended for use by ROLE_ASSISTANT and signature apps only. --> @@ -7844,7 +7935,31 @@ <!-- @SystemApi Allows an application to access shared libraries. @hide --> <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES" - android:protectionLevel="signature|installer" /> + android:protectionLevel="signature|installer" + android:featureFlag="!android.content.pm.sdk_dependency_installer" /> + + <!-- @SystemApi Allows an application to access shared libraries. + @hide --> + <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES" + android:protectionLevel="signature|installer|role" + android:featureFlag="android.content.pm.sdk_dependency_installer" /> + + <!-- @SystemApi Permission held by the system to allow binding to the dependency installer role + holder. + @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER) + @hide --> + <permission android:name="android.permission.BIND_DEPENDENCY_INSTALLER" + android:protectionLevel="signature" + android:featureFlag="android.content.pm.sdk_dependency_installer" /> + + <!-- @SystemApi Allows an application to install shared libraries of types + {@link android.content.pm.SharedLibraryInfo#TYPE_STATIC} or + {@link android.content.pm.SharedLibraryInfo#TYPE_SDK_PACKAGE}. + @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER) + @hide --> + <permission android:name="android.permission.INSTALL_DEPENDENCY_SHARED_LIBRARIES" + android:protectionLevel="signature|role" + android:featureFlag="android.content.pm.sdk_dependency_installer" /> <!-- Allows an app to log compat change usage. @hide <p>Not for use by third-party applications.</p> --> @@ -8565,27 +8680,6 @@ <permission android:name="android.permission.RESERVED_FOR_TESTING_SIGNATURE" android:protectionLevel="signature"/> - <!-- - @SystemApi - @FlaggedApi("android.media.tv.flags.media_quality_fw") - Allows an application to access its picture profile from the media quality database. - <p> Protection level: signature|privileged|vendor privileged - @hide - --> - <permission android:name="android.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE" - android:protectionLevel="signature|privileged|vendorPrivileged" - android:featureFlag="android.media.tv.flags.media_quality_fw"/> - - <!-- - @SystemApi - @FlaggedApi("android.media.tv.flags.media_quality_fw") - Allows an application to access its sound profile from the media quality database. - <p> Protection level: signature|privileged|vendor privileged - @hide - --> - <permission android:name="android.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE" - android:protectionLevel="signature|privileged|vendorPrivileged" - android:featureFlag="android.media.tv.flags.media_quality_fw"/> <!-- @SystemApi @FlaggedApi("android.content.pm.verification_service") Allows app to be the verification agent to verify packages. diff --git a/core/res/res/drawable/notification_progress.xml b/core/res/res/drawable/notification_progress.xml index 3a6b60077045..5d272fb00e34 100644 --- a/core/res/res/drawable/notification_progress.xml +++ b/core/res/res/drawable/notification_progress.xml @@ -24,9 +24,9 @@ android:segPointGap="@dimen/notification_progress_segPoint_gap"> <segments android:color="?attr/colorProgressBackgroundNormal" - android:dashGap="@dimen/notification_progress_segments_dash_gap" - android:dashWidth="@dimen/notification_progress_segments_dash_width" - android:width="@dimen/notification_progress_segments_height" /> + android:height="@dimen/notification_progress_segments_height" + android:fadedHeight="@dimen/notification_progress_segments_faded_height" + android:cornerRadius="@dimen/notification_progress_segments_corner_radius"/> <points android:color="?attr/colorProgressBackgroundNormal" android:radius="@dimen/notification_progress_points_radius" diff --git a/core/res/res/layout/list_content_simple.xml b/core/res/res/layout/list_content_simple.xml index 6f9f1e0f0f6f..961668e6bf2e 100644 --- a/core/res/res/layout/list_content_simple.xml +++ b/core/res/res/layout/list_content_simple.xml @@ -20,5 +20,6 @@ <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" + android:fitsSystemWindows="true" android:drawSelectorOnTop="false" /> diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml new file mode 100644 index 000000000000..c003820a247f --- /dev/null +++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml @@ -0,0 +1,195 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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 + --> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/status_bar_latest_event_content" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:minHeight="@dimen/notification_headerless_min_height" + android:tag="base" + > + + <ImageView + android:id="@+id/left_icon" + android:layout_width="@dimen/notification_2025_left_icon_size" + android:layout_height="@dimen/notification_2025_left_icon_size" + android:layout_gravity="center_vertical|start" + android:layout_marginStart="@dimen/notification_left_icon_start" + android:background="@drawable/notification_large_icon_outline" + android:clipToOutline="true" + android:importantForAccessibility="no" + android:scaleType="centerCrop" + android:visibility="gone" + /> + + <com.android.internal.widget.NotificationRowIconView + android:id="@+id/icon" + android:layout_width="@dimen/notification_2025_icon_circle_size" + android:layout_height="@dimen/notification_2025_icon_circle_size" + android:layout_gravity="center_vertical|start" + android:layout_marginStart="@dimen/notification_icon_circle_start" + android:background="@drawable/notification_icon_circle" + android:padding="@dimen/notification_2025_icon_circle_padding" + android:maxDrawableWidth="@dimen/notification_2025_icon_circle_size" + android:maxDrawableHeight="@dimen/notification_2025_icon_circle_size" + /> + + <FrameLayout + android:id="@+id/alternate_expand_target" + android:layout_width="@dimen/notification_2025_content_margin_start" + android:layout_height="match_parent" + android:layout_gravity="start" + android:importantForAccessibility="no" + android:focusable="false" + /> + + <LinearLayout + android:id="@+id/notification_headerless_view_row" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginStart="@dimen/notification_2025_content_margin_start" + android:orientation="horizontal" + > + + <LinearLayout + android:id="@+id/notification_headerless_view_column" + android:layout_width="0px" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:layout_marginBottom="@dimen/notification_headerless_margin_twoline" + android:layout_marginTop="@dimen/notification_headerless_margin_twoline" + android:orientation="vertical" + > + + <NotificationTopLineView + android:id="@+id/notification_top_line" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:minHeight="@dimen/notification_headerless_line_height" + android:clipChildren="false" + android:theme="@style/Theme.DeviceDefault.Notification" + > + + <!-- + NOTE: The notification_top_line_views layout contains the app_name_text. + In order to include the title view at the beginning, the Notification.Builder + has logic to hide that view whenever this title view is to be visible. + --> + + <TextView + android:id="@+id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:ellipsize="end" + android:fadingEdge="horizontal" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" + /> + + <include layout="@layout/notification_top_line_views" /> + + </NotificationTopLineView> + + <LinearLayout + android:id="@+id/notification_main_column" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + > + + <com.android.internal.widget.NotificationVanishingFrameLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="@dimen/notification_headerless_line_height" + > + <!-- This is the simplest way to keep this text vertically centered without + gravity="center_vertical" which causes jumpiness in expansion animations. --> + <include + layout="@layout/notification_template_text" + android:layout_width="match_parent" + android:layout_height="@dimen/notification_text_height" + android:layout_gravity="center_vertical" + android:layout_marginTop="0dp" + /> + </com.android.internal.widget.NotificationVanishingFrameLayout> + + <include + layout="@layout/notification_template_progress" + android:layout_width="match_parent" + android:layout_height="@dimen/notification_headerless_line_height" + /> + + </LinearLayout> + + </LinearLayout> + + <com.android.internal.widget.CachingIconView + android:id="@+id/right_icon" + android:layout_width="@dimen/notification_right_icon_size" + android:layout_height="@dimen/notification_right_icon_size" + android:layout_gravity="center_vertical|end" + android:layout_marginTop="@dimen/notification_right_icon_headerless_margin" + android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin" + android:layout_marginStart="@dimen/notification_right_icon_content_margin" + android:background="@drawable/notification_large_icon_outline" + android:clipToOutline="true" + android:importantForAccessibility="no" + android:scaleType="centerCrop" + android:maxDrawableWidth="@dimen/notification_right_icon_size" + android:maxDrawableHeight="@dimen/notification_right_icon_size" + /> + + <LinearLayout + android:id="@+id/notification_buttons_column" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_alignParentEnd="true" + android:orientation="vertical" + > + + <include layout="@layout/notification_close_button" + android:layout_width="@dimen/notification_close_button_size" + android:layout_height="@dimen/notification_close_button_size" + android:layout_gravity="end" + android:layout_marginEnd="20dp" + /> + + <FrameLayout + android:id="@+id/expand_button_touch_container" + android:layout_width="wrap_content" + android:layout_height="0dp" + android:layout_weight="1" + android:minWidth="@dimen/notification_content_margin_end" + > + + <include layout="@layout/notification_expand_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical|end" + /> + + </FrameLayout> + + </LinearLayout> + + </LinearLayout> + +</FrameLayout> diff --git a/core/res/res/layout/notification_2025_template_header.xml b/core/res/res/layout/notification_2025_template_header.xml new file mode 100644 index 000000000000..b7fe454e09d4 --- /dev/null +++ b/core/res/res/layout/notification_2025_template_header.xml @@ -0,0 +1,111 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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 + --> + +<!-- extends RelativeLayout --> +<NotificationHeaderView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/notification_header" + android:layout_width="match_parent" + android:layout_height="@dimen/notification_2025_header_height" + android:layout_marginBottom="@dimen/notification_header_margin_bottom" + android:clipChildren="false" + android:gravity="center_vertical" + android:orientation="horizontal" + android:theme="@style/Theme.DeviceDefault.Notification" + android:importantForAccessibility="no" + > + + <ImageView + android:id="@+id/left_icon" + android:layout_width="@dimen/notification_2025_left_icon_size" + android:layout_height="@dimen/notification_2025_left_icon_size" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:layout_marginStart="@dimen/notification_left_icon_start" + android:background="@drawable/notification_large_icon_outline" + android:clipToOutline="true" + android:importantForAccessibility="no" + android:scaleType="centerCrop" + android:visibility="gone" + /> + + <com.android.internal.widget.NotificationRowIconView + android:id="@+id/icon" + android:layout_width="@dimen/notification_2025_icon_circle_size" + android:layout_height="@dimen/notification_2025_icon_circle_size" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:layout_marginStart="@dimen/notification_icon_circle_start" + android:background="@drawable/notification_icon_circle" + android:padding="@dimen/notification_2025_icon_circle_padding" + android:maxDrawableWidth="@dimen/notification_2025_icon_circle_size" + android:maxDrawableHeight="@dimen/notification_2025_icon_circle_size" + /> + + <!-- extends ViewGroup --> + <NotificationTopLineView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/notification_top_line" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:layout_toStartOf="@id/notification_buttons_column" + android:layout_alignWithParentIfMissing="true" + android:clipChildren="false" + android:gravity="center_vertical" + android:paddingStart="@dimen/notification_2025_content_margin_start" + android:theme="@style/Theme.DeviceDefault.Notification" + > + + <include layout="@layout/notification_top_line_views" /> + + </NotificationTopLineView> + + <FrameLayout + android:id="@+id/alternate_expand_target" + android:layout_width="@dimen/notification_2025_content_margin_start" + android:layout_height="match_parent" + android:layout_alignParentStart="true" + android:importantForAccessibility="no" + android:focusable="false" + /> + + <LinearLayout + android:id="@+id/notification_buttons_column" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:orientation="vertical" + > + + <include layout="@layout/notification_close_button" + android:layout_width="@dimen/notification_close_button_size" + android:layout_height="@dimen/notification_close_button_size" + android:layout_gravity="end" + android:layout_marginEnd="20dp" + /> + + <include layout="@layout/notification_expand_button" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_centerVertical="true" + /> + + </LinearLayout> + +</NotificationHeaderView> diff --git a/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml b/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml index 82920bad95cd..149a5a9568f2 100644 --- a/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml +++ b/core/res/res/layout/notification_template_material_messaging_compact_heads_up.xml @@ -34,12 +34,14 @@ android:maxDrawableWidth="@dimen/notification_icon_circle_size" android:maxDrawableHeight="@dimen/notification_icon_circle_size" /> - <com.android.internal.widget.NotificationRowIconView + <com.android.internal.widget.CachingIconView android:id="@+id/conversation_icon" android:layout_width="@dimen/notification_icon_circle_size" android:layout_height="@dimen/notification_icon_circle_size" android:layout_gravity="center_vertical|start" android:layout_marginStart="@dimen/notification_icon_circle_start" + android:background="@drawable/notification_icon_circle" + android:clipToOutline="true" android:maxDrawableWidth="@dimen/notification_icon_circle_size" android:maxDrawableHeight="@dimen/notification_icon_circle_size" android:scaleType="centerCrop" diff --git a/core/res/res/values-night/colors_dynamic.xml b/core/res/res/values-night/colors_dynamic.xml new file mode 100644 index 000000000000..7e95ff4f409e --- /dev/null +++ b/core/res/res/values-night/colors_dynamic.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- Colors specific to Material themes. --> +<resources> + <color name="materialColorBackground">@color/system_background_dark</color> + <color name="materialColorControlActivated">@color/system_control_activated_dark</color> + <color name="materialColorControlHighlight">@color/system_control_highlight_dark</color> + <color name="materialColorControlNormal">@color/system_control_normal_dark</color> + <color name="materialColorError">@color/system_error_dark</color> + <color name="materialColorErrorContainer">@color/system_error_container_dark</color> + <color name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</color> + <color name="materialColorInversePrimary">@color/system_inverse_primary_dark</color> + <color name="materialColorInverseSurface">@color/system_inverse_surface_dark</color> + <color name="materialColorOnBackground">@color/system_on_background_dark</color> + <color name="materialColorOnError">@color/system_on_error_dark</color> + <color name="materialColorOnErrorContainer">@color/system_on_error_container_dark</color> + <color name="materialColorOnPrimary">@color/system_on_primary_dark</color> + <color name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</color> + <color name="materialColorOnSecondary">@color/system_on_secondary_dark</color> + <color name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</color> + <color name="materialColorOnSurface">@color/system_on_surface_dark</color> + <color name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</color> + <color name="materialColorOnTertiary">@color/system_on_tertiary_dark</color> + <color name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</color> + <color name="materialColorOutline">@color/system_outline_dark</color> + <color name="materialColorOutlineVariant">@color/system_outline_variant_dark</color> + <color name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</color> + <color name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</color> + <color name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</color> + <color name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</color> + <color name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</color> + <color name="materialColorPrimary">@color/system_primary_dark</color> + <color name="materialColorPrimaryContainer">@color/system_primary_container_dark</color> + <color name="materialColorScrim">@color/system_scrim_dark</color> + <color name="materialColorSecondary">@color/system_secondary_dark</color> + <color name="materialColorSecondaryContainer">@color/system_secondary_container_dark</color> + <color name="materialColorShadow">@color/system_shadow_dark</color> + <color name="materialColorSurface">@color/system_surface_dark</color> + <color name="materialColorSurfaceBright">@color/system_surface_bright_dark</color> + <color name="materialColorSurfaceContainer">@color/system_surface_container_dark</color> + <color name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</color> + <color name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</color> + <color name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</color> + <color name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</color> + <color name="materialColorSurfaceDim">@color/system_surface_dim_dark</color> + <color name="materialColorSurfaceTint">@color/system_surface_tint_dark</color> + <color name="materialColorSurfaceVariant">@color/system_surface_variant_dark</color> + <color name="materialColorTertiary">@color/system_tertiary_dark</color> + <color name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</color> + <color name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</color> + <color name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</color> + <color name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</color> + <color name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</color> + <color name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</color> + <color name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</color> + <color name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</color> + <color name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</color> + <color name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</color> + <color name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</color> + <color name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</color> + <color name="materialColorPrimaryFixed">@color/system_primary_fixed</color> + <color name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</color> + <color name="materialColorSecondaryFixed">@color/system_secondary_fixed</color> + <color name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</color> + <color name="materialColorTertiaryFixed">@color/system_tertiary_fixed</color> + <color name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</color> + <color name="customColorBrandA">@color/system_brand_a_dark</color> + <color name="customColorBrandB">@color/system_brand_b_dark</color> + <color name="customColorBrandC">@color/system_brand_c_dark</color> + <color name="customColorBrandD">@color/system_brand_d_dark</color> + <color name="customColorClockHour">@color/system_clock_hour_dark</color> + <color name="customColorClockMinute">@color/system_clock_minute_dark</color> + <color name="customColorClockSecond">@color/system_clock_second_dark</color> + <color name="customColorOnShadeActive">@color/system_on_shade_active_dark</color> + <color name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_dark</color> + <color name="customColorOnShadeInactive">@color/system_on_shade_inactive_dark</color> + <color name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_dark</color> + <color name="customColorOnThemeApp">@color/system_on_theme_app_dark</color> + <color name="customColorOverviewBackground">@color/system_overview_background_dark</color> + <color name="customColorShadeActive">@color/system_shade_active_dark</color> + <color name="customColorShadeDisabled">@color/system_shade_disabled_dark</color> + <color name="customColorShadeInactive">@color/system_shade_inactive_dark</color> + <color name="customColorThemeApp">@color/system_theme_app_dark</color> + <color name="customColorThemeAppRing">@color/system_theme_app_ring_dark</color> + <color name="customColorThemeNotif">@color/system_theme_notif_dark</color> + <color name="customColorUnderSurface">@color/system_under_surface_dark</color> + <color name="customColorWeatherTemp">@color/system_weather_temp_dark</color> + <color name="customColorWidgetBackground">@color/system_widget_background_dark</color> +</resources> diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml index 4d2085bbe0c7..7ac17595a278 100644 --- a/core/res/res/values-watch/themes_device_defaults.xml +++ b/core/res/res/values-watch/themes_device_defaults.xml @@ -238,16 +238,16 @@ a similar way. <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> + <item name="materialColorInverseOnSurface">@color/system_on_surface_light</item> <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> + <item name="materialColorInversePrimary">@color/system_primary_light</item> <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> + <item name="materialColorInverseSurface">@color/system_surface_light</item> <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index e6dedce8feaf..f6590b1360f8 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1218,155 +1218,132 @@ it prevent any 'false' in any of its children. --> <attr name="forceDarkAllowed" format="boolean" /> - <!-- A lower-emphasized variant of the color on the fixed secondary branding color. @hide - --> - <attr name="materialColorOnSecondaryFixedVariant" format="color"/> - <!-- A lower-emphasized variant of the color on the fixed tertiary branding color. @hide - --> - <attr name="materialColorOnTertiaryFixedVariant" format="color"/> - <!-- The container color of surface the most lowered. @hide --> - <attr name="materialColorSurfaceContainerLowest" format="color"/> - <!-- A lower-emphasized variant of the color on the fixed primary branding color. @hide --> - <attr name="materialColorOnPrimaryFixedVariant" format="color"/> - <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of - the secondary container color. @hide --> - <attr name="materialColorOnSecondaryContainer" format="color"/> - <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of - the tertiary container color. @hide --> - <attr name="materialColorOnTertiaryContainer" format="color"/> - <!-- The container color of surface slightly lowered, which replaces the previous surface - at elevation level 1. @hide --> - <attr name="materialColorSurfaceContainerLow" format="color"/> - <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of - the primary container color. @hide --> - <attr name="materialColorOnPrimaryContainer" format="color"/> - <!-- A stronger, more emphasized variant of the fixed secondary branding color. @hide --> - <attr name="materialColorSecondaryFixedDim" format="color"/> - <!-- A tonal variation of the on error color that passes accessibility guidelines for - text/iconography when drawn on top of error container. @hide --> - <attr name="materialColorOnErrorContainer" format="color"/> - <!-- The color text/iconography when drawn on top of the fixed secondary branding color. - @hide --> - <attr name="materialColorOnSecondaryFixed" format="color"/> - <!-- The "on surface" inverse color, useful for inverted backgrounds. @hide --> - <attr name="materialColorOnSurfaceInverse" format="color"/> - <!-- A stronger, more emphasized variant of the fixed tertiary branding color. @hide --> - <attr name="materialColorTertiaryFixedDim" format="color"/> - <!-- The color text/iconography when drawn on top of the fixed tertiary branding color. - @hide --> - <attr name="materialColorOnTertiaryFixed" format="color"/> - <!-- A stronger, more emphasized variant of the fixed primary branding color. @hide --> - <attr name="materialColorPrimaryFixedDim" format="color"/> - <!-- A tonal variation of the secondary color suitable for background color of container - views. @hide --> - <attr name="materialColorSecondaryContainer" format="color"/> - <!-- A tonal variation of the error color suitable for background color of container views. - @hide --> + <!-- Dynamic Tokens --> + + <!-- @hide --> + <attr name="materialColorBackground" format="color"/> + <!-- @hide --> + <attr name="materialColorControlActivated" format="color"/> + <!-- @hide --> + <attr name="materialColorControlHighlight" format="color"/> + <!-- @hide --> + <attr name="materialColorControlNormal" format="color"/> + <!-- @hide --> + <attr name="materialColorError" format="color"/> + <!-- @hide --> <attr name="materialColorErrorContainer" format="color"/> - <!-- The color text/iconography when drawn on top of the fixed primary branding color. - @hide --> - <attr name="materialColorOnPrimaryFixed" format="color"/> - <!-- The inverse color of colorPrimary. @hide --> - <attr name="materialColorPrimaryInverse" format="color"/> - <!-- A secondary branding color for the app, which stays the same between light and dark - themes. @hide --> - <attr name="materialColorSecondaryFixed" format="color"/> - <!-- The surface inverse color, useful for inverted backgrounds. @hide --> - <attr name="materialColorSurfaceInverse" format="color"/> - <!-- A tonal variation of the surface color. @hide --> - <attr name="materialColorSurfaceVariant" format="color"/> - <!-- A tonal variation of the tertiary color suitable for background color of container - views. @hide --> - <attr name="materialColorTertiaryContainer" format="color"/> - <!-- A tertiary branding color for the app, which stays the same between light and dark - themes. @hide --> - <attr name="materialColorTertiaryFixed" format="color"/> - <!-- A tonal variation of the primary color suitable for background color of container - views. @hide --> - <attr name="materialColorPrimaryContainer" format="color"/> - <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of - background. @hide --> + <!-- @hide --> + <attr name="materialColorInverseOnSurface" format="color"/> + <!-- @hide --> + <attr name="materialColorInversePrimary" format="color"/> + <!-- @hide --> + <attr name="materialColorInverseSurface" format="color"/> + <!-- @hide --> <attr name="materialColorOnBackground" format="color"/> - <!-- A primary branding color for the app, which stays the same between light and dark - themes. @hide --> - <attr name="materialColorPrimaryFixed" format="color"/> - <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of - secondary. @hide --> - <attr name="materialColorOnSecondary" format="color"/> - <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of - tertiary. @hide --> - <attr name="materialColorOnTertiary" format="color"/> - <!-- The surface color which always stay the dimmest in either dark or light theme. @hide - --> - <attr name="materialColorSurfaceDim" format="color"/> - <!-- The surface color which always stay the brightest in either dark or light theme. @hide - --> - <attr name="materialColorSurfaceBright" format="color"/> - <!-- The secondary branding color for the app, usually a bright complement to the primary - branding color. @hide --> - <attr name="materialColorSecondary" format="color"/> - <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of - error. @hide --> + <!-- @hide --> <attr name="materialColorOnError" format="color"/> - <!-- The color of surfaces such as cards, sheets, menus. @hide --> - <attr name="materialColorSurface" format="color"/> - <!-- The container color of surface slightly elevated, which replaces the previous surface - at elevation level 3. @hide --> - <attr name="materialColorSurfaceContainerHigh" format="color"/> - <!-- The tertiary branding color for the app, usually a bright complement to the primary - branding color. @hide --> - <attr name="materialColorTertiary" format="color"/> - <!-- The container color of surface the most elevated, which replaces the previous surface - variant. @hide --> - <attr name="materialColorSurfaceContainerHighest" format="color"/> - <!-- A tonal variation of the on surface color that passes accessibility guidelines for - text/iconography when drawn on top of surface variant. @hide --> + <!-- @hide --> + <attr name="materialColorOnErrorContainer" format="color"/> + <!-- @hide --> + <attr name="materialColorOnPrimary" format="color"/> + <!-- @hide --> + <attr name="materialColorOnPrimaryContainer" format="color"/> + <!-- @hide --> + <attr name="materialColorOnSecondary" format="color"/> + <!-- @hide --> + <attr name="materialColorOnSecondaryContainer" format="color"/> + <!-- @hide --> + <attr name="materialColorOnSurface" format="color"/> + <!-- @hide --> <attr name="materialColorOnSurfaceVariant" format="color"/> - <!-- A color meant to be used in element outlines. @hide --> + <!-- @hide --> + <attr name="materialColorOnTertiary" format="color"/> + <!-- @hide --> + <attr name="materialColorOnTertiaryContainer" format="color"/> + <!-- @hide --> <attr name="materialColorOutline" format="color"/> - <!-- A color meant to be used in element outlines on the surface-variant color. @hide --> + <!-- @hide --> <attr name="materialColorOutlineVariant" format="color"/> - <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of - primary. @hide --> - <attr name="materialColorOnPrimary" format="color"/> - <!-- A color that passes accessibility guidelines for text/iconography when drawn on top of - surface. @hide --> - <attr name="materialColorOnSurface" format="color"/> - <!-- The container color of surface, which replaces the previous surface at elevation level - 2. @hide --> - <attr name="materialColorSurfaceContainer" format="color"/> - <!-- The container color of surface, which replaces the previous surface at elevation level - 2. @hide --> - <attr name="materialColorSurfaceContainer" format="color"/> - <!-- The primary branding color for the app. By default, this is the color applied to the - action bar background. @hide --> + <!-- @hide --> + <attr name="materialColorPaletteKeyColorNeutral" format="color"/> + <!-- @hide --> + <attr name="materialColorPaletteKeyColorNeutralVariant" format="color"/> + <!-- @hide --> + <attr name="materialColorPaletteKeyColorPrimary" format="color"/> + <!-- @hide --> + <attr name="materialColorPaletteKeyColorSecondary" format="color"/> + <!-- @hide --> + <attr name="materialColorPaletteKeyColorTertiary" format="color"/> + <!-- @hide --> <attr name="materialColorPrimary" format="color"/> - <!-- The secondary branding color for the app, usually a bright complement to the primary - branding color. @hide --> + <!-- @hide --> + <attr name="materialColorPrimaryContainer" format="color"/> + <!-- @hide --> + <attr name="materialColorScrim" format="color"/> + <!-- @hide --> <attr name="materialColorSecondary" format="color"/> - <!-- A color that passes accessibility guidelines for text/iconography when drawn on top - of tertiary. @hide --> + <!-- @hide --> + <attr name="materialColorSecondaryContainer" format="color"/> + <!-- @hide --> + <attr name="materialColorShadow" format="color"/> + <!-- @hide --> + <attr name="materialColorSurface" format="color"/> + <!-- @hide --> + <attr name="materialColorSurfaceBright" format="color"/> + <!-- @hide --> + <attr name="materialColorSurfaceContainer" format="color"/> + <!-- @hide --> + <attr name="materialColorSurfaceContainerHigh" format="color"/> + <!-- @hide --> + <attr name="materialColorSurfaceContainerHighest" format="color"/> + <!-- @hide --> + <attr name="materialColorSurfaceContainerLow" format="color"/> + <!-- @hide --> + <attr name="materialColorSurfaceContainerLowest" format="color"/> + <!-- @hide --> + <attr name="materialColorSurfaceDim" format="color"/> + <!-- @hide --> + <attr name="materialColorSurfaceTint" format="color"/> + <!-- @hide --> + <attr name="materialColorSurfaceVariant" format="color"/> + <!-- @hide --> <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"/> + <attr name="materialColorTertiaryContainer" format="color"/> <!-- @hide --> - <attr name="customColorClockHour" format="color"/> + <attr name="materialColorTextHintInverse" format="color"/> <!-- @hide --> - <attr name="customColorClockMinute" format="color"/> + <attr name="materialColorTextPrimaryInverse" format="color"/> <!-- @hide --> - <attr name="customColorClockSecond" format="color"/> + <attr name="materialColorTextPrimaryInverseDisableOnly" format="color"/> <!-- @hide --> - <attr name="customColorThemeApp" format="color"/> + <attr name="materialColorTextSecondaryAndTertiaryInverse" format="color"/> <!-- @hide --> - <attr name="customColorOnThemeApp" format="color"/> + <attr name="materialColorTextSecondaryAndTertiaryInverseDisabled" format="color"/> <!-- @hide --> - <attr name="customColorThemeAppRing" format="color"/> + <attr name="materialColorOnPrimaryFixed" format="color"/> <!-- @hide --> - <attr name="customColorThemeNotif" format="color"/> + <attr name="materialColorOnPrimaryFixedVariant" format="color"/> + <!-- @hide --> + <attr name="materialColorOnSecondaryFixed" format="color"/> + <!-- @hide --> + <attr name="materialColorOnSecondaryFixedVariant" format="color"/> + <!-- @hide --> + <attr name="materialColorOnTertiaryFixed" format="color"/> + <!-- @hide --> + <attr name="materialColorOnTertiaryFixedVariant" format="color"/> + <!-- @hide --> + <attr name="materialColorPrimaryFixed" format="color"/> + <!-- @hide --> + <attr name="materialColorPrimaryFixedDim" format="color"/> + <!-- @hide --> + <attr name="materialColorSecondaryFixed" format="color"/> + <!-- @hide --> + <attr name="materialColorSecondaryFixedDim" format="color"/> + <!-- @hide --> + <attr name="materialColorTertiaryFixed" format="color"/> + <!-- @hide --> + <attr name="materialColorTertiaryFixedDim" format="color"/> <!-- @hide --> <attr name="customColorBrandA" format="color"/> <!-- @hide --> @@ -1376,23 +1353,41 @@ <!-- @hide --> <attr name="customColorBrandD" format="color"/> <!-- @hide --> - <attr name="customColorUnderSurface" format="color"/> + <attr name="customColorClockHour" format="color"/> <!-- @hide --> - <attr name="customColorShadeActive" format="color"/> + <attr name="customColorClockMinute" format="color"/> + <!-- @hide --> + <attr name="customColorClockSecond" 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"/> + <attr name="customColorOnThemeApp" format="color"/> <!-- @hide --> <attr name="customColorOverviewBackground" format="color"/> + <!-- @hide --> + <attr name="customColorShadeActive" format="color"/> + <!-- @hide --> + <attr name="customColorShadeDisabled" format="color"/> + <!-- @hide --> + <attr name="customColorShadeInactive" format="color"/> + <!-- @hide --> + <attr name="customColorThemeApp" format="color"/> + <!-- @hide --> + <attr name="customColorThemeAppRing" format="color"/> + <!-- @hide --> + <attr name="customColorThemeNotif" format="color"/> + <!-- @hide --> + <attr name="customColorUnderSurface" format="color"/> + <!-- @hide --> + <attr name="customColorWeatherTemp" format="color"/> + <!-- @hide --> + <attr name="customColorWidgetBackground" format="color"/> </declare-styleable> @@ -7753,14 +7748,14 @@ <!-- Used to config the segments of a NotificationProgressDrawable. --> <!-- @hide internal use only --> <declare-styleable name="NotificationProgressDrawableSegments"> - <!-- Width of the stroke. --> - <attr name="width" /> - <!-- Default color of the stroke. --> + <!-- Height of the solid segments --> + <attr name="height" /> + <!-- Height of the faded segments --> + <attr name="fadedHeight" format="dimension"/> + <!-- Corner radius of the segment rect. --> + <attr name="cornerRadius" format="dimension" /> + <!-- Default color of the segment. --> <attr name="color" /> - <!-- Length of a dash in the stroke for the dashed segments. --> - <attr name="dashWidth" /> - <!-- Gap between dashes in the stroke for the dashed segments. --> - <attr name="dashGap" /> </declare-styleable> <!-- Used to config the points of a NotificationProgressDrawable. --> @@ -7771,7 +7766,7 @@ <!-- Inset of the point icon or rect. --> <attr name="inset" /> <!-- Corner radius of the point rect. --> - <attr name="cornerRadius" format="dimension" /> + <attr name="cornerRadius"/> <!-- Default color of the point rect. --> <attr name="color" /> </declare-styleable> @@ -10285,22 +10280,25 @@ </declare-styleable> <!-- @hide --> + <attr name="modifierState"> + <flag name="META" value="0x10000" /> + <flag name="CTRL" value="0x1000" /> + <flag name="ALT" value="0x02" /> + <flag name="SHIFT" value="0x1" /> + <flag name="SYM" value="0x4" /> + <flag name="FUNCTION" value="0x8" /> + <flag name="CAPS_LOCK" value="0x100000" /> + <flag name="NUM_LOCK" value="0x200000" /> + <flag name="SCROLL_LOCK" value="0x400000" /> + </attr> + + <!-- @hide --> <declare-styleable name="HardwareDefinedShortcut"> <attr name="keycode" /> <!-- The values are taken from public constants for modifier state defined in {@see KeyEvent.java}. Here we allow multiple modifier flags as value, since this represents the modifier state --> - <attr name="modifierState"> - <flag name="META" value="0x10000" /> - <flag name="CTRL" value="0x1000" /> - <flag name="ALT" value="0x02" /> - <flag name="SHIFT" value="0x1" /> - <flag name="SYM" value="0x4" /> - <flag name="FUNCTION" value="0x8" /> - <flag name="CAPS_LOCK" value="0x100000" /> - <flag name="NUM_LOCK" value="0x200000" /> - <flag name="SCROLL_LOCK" value="0x400000" /> - </attr> + <attr name="modifierState" /> <attr name="outKeycode" /> </declare-styleable> @@ -10309,6 +10307,11 @@ <attr name="keycode" /> </declare-styleable> + <declare-styleable name="Bookmark"> + <attr name="keycode" /> + <attr name="modifierState" /> + </declare-styleable> + <declare-styleable name="MediaRouteButton"> <!-- This drawable is a state list where the "activated" state indicates active media routing. Non-activated indicates diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 41dec3776b5c..7ef539492aa4 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1855,13 +1855,23 @@ {@link android.R.styleable#AndroidManifestProcess process} tag, or to an {@link android.R.styleable#AndroidManifestApplication application} tag (to supply a default setting for all application components). --> - <attr name="memtagMode"> + <attr name="memtagMode"> <enum name="default" value="-1" /> <enum name="off" value="0" /> <enum name="async" value="1" /> <enum name="sync" value="2" /> </attr> + <!-- This attribute will be used to override app compatibility mode on 16 KB devices. + If set to enabled, Natives lib will be extracted from APK if they are not page aligned on + 16 KB device. 4 KB natives libs will be loaded app-compat mode if they are eligible. + @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) --> + <attr name="pageSizeCompat"> + <enum name="enabled" value="5" /> + <enum name="disabled" value="6" /> + </attr> + + <!-- Attribution tag to be used for permission sub-attribution if a permission is checked in {@link android.content.Context#sendBroadcast(Intent, String)}. Multiple tags can be specified separated by '|'. @@ -2212,6 +2222,9 @@ <attr name="memtagMode" /> + <!-- @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) --> + <attr name="pageSizeCompat" /> + <!-- If {@code true} enables automatic zero initialization of all native heap allocations. --> <attr name="nativeHeapZeroInitialized" format="boolean" /> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index f5bb554b0b32..13dd4a35564c 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -238,393 +238,319 @@ <color name="conversation_important_highlight">#F9AB00</color> - <!--Lightest shade of the Primary color used by the system. White. - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Lightest shade of the Primary color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_0">#FFFFFF</color> - <!--Shade of the Primary system color at 99% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_10">#FEFBFF</color> - <!--Shade of the Primary system color at 95% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_50">#EEF0FF</color> - <!--Shade of the Primary system color at 90% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_100">#D9E2FF</color> - <!--Shade of the Primary system color at 80% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_200">#B0C6FF</color> - <!--Shade of the Primary system color at 70% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_300">#94AAE4</color> - <!--Shade of the Primary system color at 60% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_400">#7A90C8</color> - <!--Shade of the Primary system color at 50% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_500">#6076AC</color> - <!--Shade of the Primary system color at 40% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_600">#475D92</color> - <!--Shade of the Primary system color at 30% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_700">#2F4578</color> - <!--Shade of the Primary system color at 20% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_800">#152E60</color> - <!--Shade of the Primary system color at 10% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Primary system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_900">#001945</color> - <!--Darkest shade of the Primary color used by the system. Black. - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Darkest shade of the Primary color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent1_1000">#000000</color> - - <!--Lightest shade of the Secondary color used by the system. White. - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Lightest shade of the Secondary color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_0">#FFFFFF</color> - <!--Shade of the Secondary system color at 99% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_10">#FEFBFF</color> - <!--Shade of the Secondary system color at 95% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_50">#EEF0FF</color> - <!--Shade of the Secondary system color at 90% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_100">#DCE2F9</color> - <!--Shade of the Secondary system color at 80% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_200">#C0C6DC</color> - <!--Shade of the Secondary system color at 70% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_300">#A4ABC1</color> - <!--Shade of the Secondary system color at 60% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_400">#8A90A5</color> - <!--Shade of the Secondary system color at 50% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_500">#70778B</color> - <!--Shade of the Secondary system color at 40% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_600">#575E71</color> - <!--Shade of the Secondary system color at 30% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_700">#404659</color> - <!--Shade of the Secondary system color at 20% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_800">#2A3042</color> - <!--Shade of the Secondary system color at 10% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_900">#151B2C</color> - <!--Darkest shade of the Secondary color used by the system. Black. - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Darkest shade of the Secondary color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent2_1000">#000000</color> - - <!--Lightest shade of the Tertiary color used by the system. White. - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Lightest shade of the Tertiary color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_0">#FFFFFF</color> - <!--Shade of the Tertiary system color at 99% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_10">#FFFBFF</color> - <!--Shade of the Tertiary system color at 95% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_50">#FFEBFA</color> - <!--Shade of the Tertiary system color at 90% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_100">#FDD7FA</color> - <!--Shade of the Tertiary system color at 80% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_200">#E0BBDD</color> - <!--Shade of the Tertiary system color at 70% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_300">#C3A0C1</color> - <!--Shade of the Tertiary system color at 60% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_400">#A886A6</color> - <!--Shade of the Tertiary system color at 50% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_500">#8C6D8C</color> - <!--Shade of the Tertiary system color at 40% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_600">#725572</color> - <!--Shade of the Tertiary system color at 30% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_700">#593D59</color> - <!--Shade of the Tertiary system color at 20% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_800">#412742</color> - <!--Shade of the Tertiary system color at 10% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Tertiary system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_900">#2A122C</color> - <!--Darkest shade of the Tertiary color used by the system. Black. - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Darkest shade of the Tertiary color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_accent3_1000">#000000</color> - - <!--Lightest shade of the Neutral color used by the system. White. - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Lightest shade of the Neutral color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_0">#FFFFFF</color> - <!--Shade of the Neutral system color at 99% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_10">#FEFBFF</color> - <!--Shade of the Neutral system color at 95% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_50">#F1F0F7</color> - <!--Shade of the Neutral system color at 90% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_100">#E2E2E9</color> - <!--Shade of the Neutral system color at 80% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_200">#C6C6CD</color> - <!--Shade of the Neutral system color at 70% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_300">#ABABB1</color> - <!--Shade of the Neutral system color at 60% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_400">#909097</color> - <!--Shade of the Neutral system color at 50% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_500">#76777D</color> - <!--Shade of the Neutral system color at 40% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_600">#5D5E64</color> - <!--Shade of the Neutral system color at 30% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_700">#45464C</color> - <!--Shade of the Neutral system color at 20% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_800">#2F3036</color> - <!--Shade of the Neutral system color at 10% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Neutral system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_900">#1A1B20</color> - <!--Darkest shade of the Neutral color used by the system. Black. - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Darkest shade of the Neutral color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral1_1000">#000000</color> - - <!--Lightest shade of the Secondary Neutral color used by the system. White. - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Lightest shade of the Secondary Neutral color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_0">#FFFFFF</color> - <!--Shade of the Secondary Neutral system color at 99% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_10">#FEFBFF</color> - <!--Shade of the Secondary Neutral system color at 95% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_50">#F0F0FA</color> - <!--Shade of the Secondary Neutral system color at 90% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_100">#E1E2EC</color> - <!--Shade of the Secondary Neutral system color at 80% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_200">#C5C6D0</color> - <!--Shade of the Secondary Neutral system color at 70% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_300">#A9ABB4</color> - <!--Shade of the Secondary Neutral system color at 60% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_400">#8F9099</color> - <!--Shade of the Secondary Neutral system color at 50% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_500">#757780</color> - <!--Shade of the Secondary Neutral system color at 40% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_600">#5C5E67</color> - <!--Shade of the Secondary Neutral system color at 30% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_700">#44464F</color> - <!--Shade of the Secondary Neutral system color at 20% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_800">#2E3038</color> - <!--Shade of the Secondary Neutral system color at 10% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Shade of the Secondary Neutral system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_900">#191B23</color> - <!--Darkest shade of the Secondary Neutral color used by the system. Black. - This value can be overlaid at runtime by OverlayManager RROs.--> + <!--Darkest shade of the Secondary Neutral color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_neutral2_1000">#000000</color> - - <!-- Lightest shade of the error color used by the system. White. - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_0">#ffffff</color> - <!-- Shade of the error system color at 99% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_10">#FFFBF9</color> - <!-- Shade of the error system color at 95% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_50">#FCEEEE</color> - <!-- Shade of the error system color at 90% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_100">#F9DEDC</color> - <!-- Shade of the error system color at 80% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_200">#F2B8B5</color> - <!-- Shade of the error system color at 70% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_300">#EC928E</color> - <!-- Shade of the error system color at 60% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_400">#E46962</color> - <!-- Shade of the error system color at 49% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_500">#DC362E</color> - <!-- Shade of the error system color at 40% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_600">#B3261E</color> - <!-- Shade of the error system color at 30% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_700">#8C1D18</color> - <!-- Shade of the error system color at 20% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_800">#601410</color> - <!-- Shade of the error system color at 10% perceptual luminance (L* in L*a*b* color space). - This value can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_error_900">#410E0B</color> - <!-- Darkest shade of the error color used by the system. Black. - This value can be overlaid at runtime by OverlayManager RROs. --> + <!--Lightest shade of the Error color used by the system. White. This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_0">#FFFFFF</color> + <!--Shade of the Error system color at 99% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_10">#FFFBFF</color> + <!--Shade of the Error system color at 95% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_50">#FFEDEA</color> + <!--Shade of the Error system color at 90% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_100">#FFDAD6</color> + <!--Shade of the Error system color at 80% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_200">#FFB4AB</color> + <!--Shade of the Error system color at 70% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_300">#FF897D</color> + <!--Shade of the Error system color at 60% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_400">#FF5449</color> + <!--Shade of the Error system color at 50% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_500">#DE3730</color> + <!--Shade of the Error system color at 40% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_600">#BA1A1A</color> + <!--Shade of the Error system color at 30% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_700">#93000A</color> + <!--Shade of the Error system color at 20% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_800">#690005</color> + <!--Shade of the Error system color at 10% perceptual luminance (L* in L*a*b* color space). This value can be overlaid at runtime by OverlayManager RROs.--> + <color name="system_error_900">#410002</color> + <!--Darkest shade of the Error color used by the system. Black. This value can be overlaid at runtime by OverlayManager RROs.--> <color name="system_error_1000">#000000</color> - <!-- Colors used in Android system, from design system. - These values can be overlaid at runtime by OverlayManager RROs. --> - <color name="system_primary_container_light">#D9E2FF</color> - <color name="system_on_primary_container_light">#001945</color> - <color name="system_primary_light">#475D92</color> + <!--Colors used in Android system, from design system. These values can be overlaid at runtime by OverlayManager RROs.--><color name="system_background_light">#FAF8FF</color> + <color name="system_control_activated_light">#D9E2FF</color> + <color name="system_control_highlight_light">#000000</color> + <color name="system_control_normal_light">#44464F</color> + <color name="system_error_light">#BA1A1A</color> + <color name="system_error_container_light">#FFDAD6</color> + <color name="system_inverse_on_surface_light">#F1F0F7</color> + <color name="system_inverse_primary_light">#B0C6FF</color> + <color name="system_inverse_surface_light">#2F3036</color> + <color name="system_on_background_light">#1A1B20</color> + <color name="system_on_error_light">#FFFFFF</color> + <color name="system_on_error_container_light">#93000A</color> <color name="system_on_primary_light">#FFFFFF</color> - <color name="system_secondary_container_light">#DCE2F9</color> - <color name="system_on_secondary_container_light">#151B2C</color> - <color name="system_secondary_light">#575E71</color> + <color name="system_on_primary_container_light">#2F4578</color> <color name="system_on_secondary_light">#FFFFFF</color> - <color name="system_tertiary_container_light">#FDD7FA</color> - <color name="system_on_tertiary_container_light">#2A122C</color> - <color name="system_tertiary_light">#725572</color> + <color name="system_on_secondary_container_light">#404659</color> + <color name="system_on_surface_light">#1A1B20</color> + <color name="system_on_surface_variant_light">#44464F</color> <color name="system_on_tertiary_light">#FFFFFF</color> - <color name="system_background_light">#FAF8FF</color> - <color name="system_on_background_light">#1A1B20</color> + <color name="system_on_tertiary_container_light">#593D59</color> + <color name="system_outline_light">#757780</color> + <color name="system_outline_variant_light">#C5C6D0</color> + <color name="system_palette_key_color_neutral_light">#76777D</color> + <color name="system_palette_key_color_neutral_variant_light">#757780</color> + <color name="system_palette_key_color_primary_light">#6076AC</color> + <color name="system_palette_key_color_secondary_light">#70778B</color> + <color name="system_palette_key_color_tertiary_light">#8C6D8C</color> + <color name="system_primary_light">#475D92</color> + <color name="system_primary_container_light">#D9E2FF</color> + <color name="system_scrim_light">#000000</color> + <color name="system_secondary_light">#575E71</color> + <color name="system_secondary_container_light">#DCE2F9</color> + <color name="system_shadow_light">#000000</color> <color name="system_surface_light">#FAF8FF</color> - <color name="system_on_surface_light">#1A1B20</color> - <color name="system_surface_container_low_light">#F4F3FA</color> - <color name="system_surface_container_lowest_light">#FFFFFF</color> + <color name="system_surface_bright_light">#FAF8FF</color> <color name="system_surface_container_light">#EEEDF4</color> <color name="system_surface_container_high_light">#E8E7EF</color> <color name="system_surface_container_highest_light">#E2E2E9</color> - <color name="system_surface_bright_light">#FAF8FF</color> + <color name="system_surface_container_low_light">#F4F3FA</color> + <color name="system_surface_container_lowest_light">#FFFFFF</color> <color name="system_surface_dim_light">#DAD9E0</color> + <color name="system_surface_tint_light">#475D92</color> <color name="system_surface_variant_light">#E1E2EC</color> - <color name="system_on_surface_variant_light">#44464F</color> - <color name="system_outline_light">#757780</color> - <color name="system_outline_variant_light">#C5C6D0</color> - <color name="system_error_light">#BA1A1A</color> - <color name="system_on_error_light">#FFFFFF</color> - <color name="system_error_container_light">#FFDAD6</color> - <color name="system_on_error_container_light">#410002</color> - <color name="system_control_activated_light">#D9E2FF</color> - <color name="system_control_normal_light">#44464F</color> - <color name="system_control_highlight_light">#000000</color> -<color name="system_text_primary_inverse_light">#E2E2E9</color> - <color name="system_text_secondary_and_tertiary_inverse_light">#C5C6D0</color> + <color name="system_tertiary_light">#725572</color> + <color name="system_tertiary_container_light">#FDD7FA</color> + <color name="system_text_hint_inverse_light">#E2E2E9</color> + <color name="system_text_primary_inverse_light">#E2E2E9</color> <color name="system_text_primary_inverse_disable_only_light">#E2E2E9</color> + <color name="system_text_secondary_and_tertiary_inverse_light">#C5C6D0</color> <color name="system_text_secondary_and_tertiary_inverse_disabled_light">#E2E2E9</color> - <color name="system_text_hint_inverse_light">#E2E2E9</color> - <color name="system_palette_key_color_primary_light">#6076AC</color> - <color name="system_palette_key_color_secondary_light">#70778B</color> - <color name="system_palette_key_color_tertiary_light">#8C6D8C</color> - <color name="system_palette_key_color_neutral_light">#76777D</color> - <color name="system_palette_key_color_neutral_variant_light">#757780</color> - <color name="system_primary_container_dark">#2F4578</color> - <color name="system_on_primary_container_dark">#D9E2FF</color> - <color name="system_primary_dark">#B0C6FF</color> + <color name="system_background_dark">#121318</color> + <color name="system_control_activated_dark">#2F4578</color> + <color name="system_control_highlight_dark">#FFFFFF</color> + <color name="system_control_normal_dark">#C5C6D0</color> + <color name="system_error_dark">#FFB4AB</color> + <color name="system_error_container_dark">#93000A</color> + <color name="system_inverse_on_surface_dark">#2F3036</color> + <color name="system_inverse_primary_dark">#475D92</color> + <color name="system_inverse_surface_dark">#E2E2E9</color> + <color name="system_on_background_dark">#E2E2E9</color> + <color name="system_on_error_dark">#690005</color> + <color name="system_on_error_container_dark">#FFDAD6</color> <color name="system_on_primary_dark">#152E60</color> - <color name="system_secondary_container_dark">#404659</color> - <color name="system_on_secondary_container_dark">#DCE2F9</color> - <color name="system_secondary_dark">#C0C6DC</color> + <color name="system_on_primary_container_dark">#D9E2FF</color> <color name="system_on_secondary_dark">#2A3042</color> - <color name="system_tertiary_container_dark">#593D59</color> - <color name="system_on_tertiary_container_dark">#FDD7FA</color> - <color name="system_tertiary_dark">#E0BBDD</color> + <color name="system_on_secondary_container_dark">#DCE2F9</color> + <color name="system_on_surface_dark">#E2E2E9</color> + <color name="system_on_surface_variant_dark">#C5C6D0</color> <color name="system_on_tertiary_dark">#412742</color> - <color name="system_background_dark">#121318</color> - <color name="system_on_background_dark">#E2E2E9</color> + <color name="system_on_tertiary_container_dark">#FDD7FA</color> + <color name="system_outline_dark">#8F9099</color> + <color name="system_outline_variant_dark">#44464F</color> + <color name="system_palette_key_color_neutral_dark">#76777D</color> + <color name="system_palette_key_color_neutral_variant_dark">#757780</color> + <color name="system_palette_key_color_primary_dark">#6076AC</color> + <color name="system_palette_key_color_secondary_dark">#70778B</color> + <color name="system_palette_key_color_tertiary_dark">#8C6D8C</color> + <color name="system_primary_dark">#B0C6FF</color> + <color name="system_primary_container_dark">#2F4578</color> + <color name="system_scrim_dark">#000000</color> + <color name="system_secondary_dark">#C0C6DC</color> + <color name="system_secondary_container_dark">#404659</color> + <color name="system_shadow_dark">#000000</color> <color name="system_surface_dark">#121318</color> - <color name="system_on_surface_dark">#E2E2E9</color> - <color name="system_surface_container_low_dark">#1A1B20</color> - <color name="system_surface_container_lowest_dark">#0C0E13</color> + <color name="system_surface_bright_dark">#38393F</color> <color name="system_surface_container_dark">#1E1F25</color> <color name="system_surface_container_high_dark">#282A2F</color> <color name="system_surface_container_highest_dark">#33343A</color> - <color name="system_surface_bright_dark">#38393F</color> + <color name="system_surface_container_low_dark">#1A1B20</color> + <color name="system_surface_container_lowest_dark">#0C0E13</color> <color name="system_surface_dim_dark">#121318</color> + <color name="system_surface_tint_dark">#B0C6FF</color> <color name="system_surface_variant_dark">#44464F</color> - <color name="system_on_surface_variant_dark">#C5C6D0</color> - <color name="system_outline_dark">#8F9099</color> - <color name="system_outline_variant_dark">#44464F</color> - <color name="system_error_dark">#FFB4AB</color> - <color name="system_on_error_dark">#690005</color> - <color name="system_error_container_dark">#93000A</color> - <color name="system_on_error_container_dark">#FFDAD6</color> - <color name="system_control_activated_dark">#2F4578</color> - <color name="system_control_normal_dark">#C5C6D0</color> - <color name="system_control_highlight_dark">#FFFFFF</color> + <color name="system_tertiary_dark">#E0BBDD</color> + <color name="system_tertiary_container_dark">#593D59</color> + <color name="system_text_hint_inverse_dark">#1A1B20</color> <color name="system_text_primary_inverse_dark">#1A1B20</color> - <color name="system_text_secondary_and_tertiary_inverse_dark">#44464F</color> <color name="system_text_primary_inverse_disable_only_dark">#1A1B20</color> + <color name="system_text_secondary_and_tertiary_inverse_dark">#44464F</color> <color name="system_text_secondary_and_tertiary_inverse_disabled_dark">#1A1B20</color> - <color name="system_text_hint_inverse_dark">#1A1B20</color> - <color name="system_palette_key_color_primary_dark">#6076AC</color> - <color name="system_palette_key_color_secondary_dark">#70778B</color> - <color name="system_palette_key_color_tertiary_dark">#8C6D8C</color> - <color name="system_palette_key_color_neutral_dark">#76777D</color> - <color name="system_palette_key_color_neutral_variant_dark">#757780</color> - <color name="system_primary_fixed">#D9E2FF</color> - <color name="system_primary_fixed_dim">#B0C6FF</color> <color name="system_on_primary_fixed">#001945</color> <color name="system_on_primary_fixed_variant">#2F4578</color> - <color name="system_secondary_fixed">#DCE2F9</color> - <color name="system_secondary_fixed_dim">#C0C6DC</color> <color name="system_on_secondary_fixed">#151B2C</color> <color name="system_on_secondary_fixed_variant">#404659</color> - <color name="system_tertiary_fixed">#FDD7FA</color> - <color name="system_tertiary_fixed_dim">#E0BBDD</color> <color name="system_on_tertiary_fixed">#2A122C</color> <color name="system_on_tertiary_fixed_variant">#593D59</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">#373D50</color> - <color name="system_clock_minute_light">#3D5487</color> - <color name="system_clock_second_light">#4F659A</color> - <color name="system_theme_app_light">#D9E2FF</color> - <color name="system_on_theme_app_light">#475D92</color> - <color name="system_theme_app_ring_light">#94AAE4</color> - <color name="system_theme_notif_light">#E0BBDD</color> + <color name="system_primary_fixed">#D9E2FF</color> + <color name="system_primary_fixed_dim">#B0C6FF</color> + <color name="system_secondary_fixed">#DCE2F9</color> + <color name="system_secondary_fixed_dim">#C0C6DC</color> + <color name="system_tertiary_fixed">#FDD7FA</color> + <color name="system_tertiary_fixed_dim">#E0BBDD</color> <color name="system_brand_a_light">#475D92</color> <color name="system_brand_b_light">#6E7488</color> <color name="system_brand_c_light">#5E73A9</color> <color name="system_brand_d_light">#8A6A89</color> - <color name="system_under_surface_light">#000000</color> -<color name="system_shade_active_light">#D9E2FF</color> + <color name="system_clock_hour_light">#373D50</color> + <color name="system_clock_minute_light">#3D5487</color> + <color name="system_clock_second_light">#725572</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_on_theme_app_light">#475D92</color> <color name="system_overview_background_light">#C5C6D0</color> - <color name="system_widget_background_dark">#152E60</color> - <color name="system_clock_hour_dark">#8A90A5</color> - <color name="system_clock_minute_dark">#D9E2FF</color> - <color name="system_clock_second_dark">#B0C6FF</color> - <color name="system_theme_app_dark">#2F4578</color> - <color name="system_on_theme_app_dark">#B0C6FF</color> - <color name="system_theme_app_ring_dark">#94AAE4</color> - <color name="system_theme_notif_dark">#FDD7FA</color> + <color name="system_shade_active_light">#D9E2FF</color> + <color name="system_shade_disabled_light">#0C0E13</color> + <color name="system_shade_inactive_light">#2F3036</color> + <color name="system_theme_app_light">#D9E2FF</color> + <color name="system_theme_app_ring_light">#94AAE4</color> + <color name="system_theme_notif_light">#E0BBDD</color> + <color name="system_under_surface_light">#000000</color> + <color name="system_weather_temp_light">#4F659A</color> + <color name="system_widget_background_light">#EEF0FF</color> <color name="system_brand_a_dark">#B0C6FF</color> <color name="system_brand_b_dark">#DCE2F9</color> <color name="system_brand_c_dark">#7A90C8</color> <color name="system_brand_d_dark">#FDD7FA</color> - <color name="system_under_surface_dark">#000000</color> -<color name="system_shade_active_dark">#D9E2FF</color> + <color name="system_clock_hour_dark">#8A90A5</color> + <color name="system_clock_minute_dark">#D9E2FF</color> + <color name="system_clock_second_dark">#FDD7FA</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_on_theme_app_dark">#B0C6FF</color> <color name="system_overview_background_dark">#50525A</color> + <color name="system_shade_active_dark">#D9E2FF</color> + <color name="system_shade_disabled_dark">#0C0E13</color> + <color name="system_shade_inactive_dark">#2F3036</color> + <color name="system_theme_app_dark">#2F4578</color> + <color name="system_theme_app_ring_dark">#94AAE4</color> + <color name="system_theme_notif_dark">#FDD7FA</color> + <color name="system_under_surface_dark">#000000</color> + <color name="system_weather_temp_dark">#B0C6FF</color> + <color name="system_widget_background_dark">#152E60</color> <!-- Accessibility shortcut icon background color --> <color name="accessibility_feature_background">#5F6368</color> <!-- Google grey 700 --> diff --git a/core/res/res/values/colors_dynamic.xml b/core/res/res/values/colors_dynamic.xml new file mode 100644 index 000000000000..ab283eb3c6c8 --- /dev/null +++ b/core/res/res/values/colors_dynamic.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<!-- Colors specific to Material themes. --> +<resources> + <color name="materialColorBackground">@color/system_background_light</color> + <color name="materialColorControlActivated">@color/system_control_activated_light</color> + <color name="materialColorControlHighlight">@color/system_control_highlight_light</color> + <color name="materialColorControlNormal">@color/system_control_normal_light</color> + <color name="materialColorError">@color/system_error_light</color> + <color name="materialColorErrorContainer">@color/system_error_container_light</color> + <color name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</color> + <color name="materialColorInversePrimary">@color/system_inverse_primary_light</color> + <color name="materialColorInverseSurface">@color/system_inverse_surface_light</color> + <color name="materialColorOnBackground">@color/system_on_background_light</color> + <color name="materialColorOnError">@color/system_on_error_light</color> + <color name="materialColorOnErrorContainer">@color/system_on_error_container_light</color> + <color name="materialColorOnPrimary">@color/system_on_primary_light</color> + <color name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</color> + <color name="materialColorOnSecondary">@color/system_on_secondary_light</color> + <color name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</color> + <color name="materialColorOnSurface">@color/system_on_surface_light</color> + <color name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</color> + <color name="materialColorOnTertiary">@color/system_on_tertiary_light</color> + <color name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</color> + <color name="materialColorOutline">@color/system_outline_light</color> + <color name="materialColorOutlineVariant">@color/system_outline_variant_light</color> + <color name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</color> + <color name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</color> + <color name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</color> + <color name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</color> + <color name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</color> + <color name="materialColorPrimary">@color/system_primary_light</color> + <color name="materialColorPrimaryContainer">@color/system_primary_container_light</color> + <color name="materialColorScrim">@color/system_scrim_light</color> + <color name="materialColorSecondary">@color/system_secondary_light</color> + <color name="materialColorSecondaryContainer">@color/system_secondary_container_light</color> + <color name="materialColorShadow">@color/system_shadow_light</color> + <color name="materialColorSurface">@color/system_surface_light</color> + <color name="materialColorSurfaceBright">@color/system_surface_bright_light</color> + <color name="materialColorSurfaceContainer">@color/system_surface_container_light</color> + <color name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</color> + <color name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</color> + <color name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</color> + <color name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</color> + <color name="materialColorSurfaceDim">@color/system_surface_dim_light</color> + <color name="materialColorSurfaceTint">@color/system_surface_tint_light</color> + <color name="materialColorSurfaceVariant">@color/system_surface_variant_light</color> + <color name="materialColorTertiary">@color/system_tertiary_light</color> + <color name="materialColorTertiaryContainer">@color/system_tertiary_container_light</color> + <color name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</color> + <color name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</color> + <color name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</color> + <color name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</color> + <color name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</color> + <color name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</color> + <color name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</color> + <color name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</color> + <color name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</color> + <color name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</color> + <color name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</color> + <color name="materialColorPrimaryFixed">@color/system_primary_fixed</color> + <color name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</color> + <color name="materialColorSecondaryFixed">@color/system_secondary_fixed</color> + <color name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</color> + <color name="materialColorTertiaryFixed">@color/system_tertiary_fixed</color> + <color name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</color> + <color name="customColorBrandA">@color/system_brand_a_light</color> + <color name="customColorBrandB">@color/system_brand_b_light</color> + <color name="customColorBrandC">@color/system_brand_c_light</color> + <color name="customColorBrandD">@color/system_brand_d_light</color> + <color name="customColorClockHour">@color/system_clock_hour_light</color> + <color name="customColorClockMinute">@color/system_clock_minute_light</color> + <color name="customColorClockSecond">@color/system_clock_second_light</color> + <color name="customColorOnShadeActive">@color/system_on_shade_active_light</color> + <color name="customColorOnShadeActiveVariant">@color/system_on_shade_active_variant_light</color> + <color name="customColorOnShadeInactive">@color/system_on_shade_inactive_light</color> + <color name="customColorOnShadeInactiveVariant">@color/system_on_shade_inactive_variant_light</color> + <color name="customColorOnThemeApp">@color/system_on_theme_app_light</color> + <color name="customColorOverviewBackground">@color/system_overview_background_light</color> + <color name="customColorShadeActive">@color/system_shade_active_light</color> + <color name="customColorShadeDisabled">@color/system_shade_disabled_light</color> + <color name="customColorShadeInactive">@color/system_shade_inactive_light</color> + <color name="customColorThemeApp">@color/system_theme_app_light</color> + <color name="customColorThemeAppRing">@color/system_theme_app_ring_light</color> + <color name="customColorThemeNotif">@color/system_theme_notif_light</color> + <color name="customColorUnderSurface">@color/system_under_surface_light</color> + <color name="customColorWeatherTemp">@color/system_weather_temp_light</color> + <color name="customColorWidgetBackground">@color/system_widget_background_light</color> +</resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 969ee2e16deb..3f4ea2df9266 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4205,9 +4205,17 @@ must match the value of config_cameraLaunchGestureSensorType in OEM's HAL --> <string translatable="false" name="config_cameraLaunchGestureSensorStringType"></string> + <!-- Allow the gesture to double tap the power button to trigger a target action. --> + <bool name="config_doubleTapPowerGestureEnabled">true</bool> <!-- Allow the gesture to double tap the power button twice to start the camera while the device is non-interactive. --> <bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool> + <!-- Allow the gesture to double tap the power button twice to launch the wallet. --> + <bool name="config_walletDoubleTapPowerGestureEnabled">true</bool> + <!-- Default target action for double tap of the power button gesture. + 0: Launch camera + 1: Launch wallet --> + <integer name="config_defaultDoubleTapPowerGestureAction">0</integer> <!-- Allow the gesture to quick tap the power button multiple times to start the emergency sos experience while the device is non-interactive. --> @@ -5898,6 +5906,11 @@ <!-- <item>com.android.settings</item> --> </string-array> + <!-- Certificate digests for trusted apps that will be allowed to obtain the knownSigner + SET_DEFAULT_ACCOUNT_FOR_CONTACTS permissions. The digest should be computed over the DER + encoding of the trusted certificate using the SHA-256 digest algorithm. --> + <string-array name="config_setContactsDefaultAccountKnownSigners"> + </string-array> <!-- Class name of the custom country detector to be used. --> <string name="config_customCountryDetector" translatable="false">com.android.server.location.ComprehensiveCountryDetector</string> @@ -6567,7 +6580,7 @@ </string-array> <!-- the number of the max cached processes in the system. --> - <integer name="config_customizedMaxCachedProcesses">32</integer> + <integer name="config_customizedMaxCachedProcesses">1024</integer> <!-- Whether this device should support taking app snapshots on closure --> <bool name="config_disableTaskSnapshots">false</bool> @@ -7212,9 +7225,12 @@ <!-- Package for opening identity check settings page [CHAR LIMIT=NONE] [DO NOT TRANSLATE] --> <string name="identity_check_settings_package_name">com\u002eandroid\u002esettings</string> - <!-- The name of the service for forensic backup transport. --> - <string name="config_forensicBackupTransport" translatable="false"></string> + <!-- The name of the service for forensic event transport. --> + <string name="config_forensicEventTransport" translatable="false"></string> <!-- Whether to enable fp unlock when screen turns off on udfps devices --> <bool name="config_screen_off_udfps_enabled">false</bool> + + <!-- The name of the system package that will hold the dependency installer role. --> + <string name="config_systemDependencyInstaller" translatable="false" /> </resources> diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml index 31e9913dd988..4ec27a31df8c 100644 --- a/core/res/res/values/config_telephony.xml +++ b/core/res/res/values/config_telephony.xml @@ -318,6 +318,12 @@ <bool name="config_oem_enabled_satellite_access_allow">true</bool> <java-symbol type="bool" name="config_oem_enabled_satellite_access_allow" /> + <!-- Whether the satellite modem support concurrent TN scanning while device is in + NTN mode. + --> + <bool name="config_satellite_modem_support_concurrent_tn_scanning">true</bool> + <java-symbol type="bool" name="config_satellite_modem_support_concurrent_tn_scanning" /> + <!-- The time duration in seconds which is used to decide whether the Location returned from LocationManager#getLastKnownLocation is fresh. diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index db752065289e..375748786817 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -247,9 +247,14 @@ <!-- Default padding for dialogs. --> <dimen name="dialog_padding">16dp</dimen> - <!-- The margin on the start of the content view (accommodates the icon) --> + <!-- The margin on the start of the content view (accommodates the icon) + This represents 16dp for the left margin + 24dp for the icon + 12dp for the right margin --> <dimen name="notification_content_margin_start">52dp</dimen> + <!-- The margin on the start of the content view (accommodates the icon), 2025 redesign version + This represents 16dp for the left margin + 40dp for the icon + 16dp for the right margin --> + <dimen name="notification_2025_content_margin_start">72dp</dimen> + <!-- The margin on the end of most content views (ignores the expander) --> <dimen name="notification_content_margin_end">16dp</dimen> @@ -310,6 +315,9 @@ <!-- height of the notification header --> <dimen name="notification_header_height">56dp</dimen> + <!-- height of the notification header (2025 redesign version) --> + <dimen name="notification_2025_header_height">72dp</dimen> + <!-- The height of the background for a notification header on a group --> <dimen name="notification_header_background_height">49.5dp</dimen> @@ -331,9 +339,17 @@ <!-- size (width and height) of the circle around the icon in the notification header --> <dimen name="notification_icon_circle_size">24dp</dimen> + <!-- size (width and height) of the circular icon in the notification header + (2025 redesign version) --> + <dimen name="notification_2025_icon_circle_size">40dp</dimen> + <!-- padding between the notification icon and the circle containing it --> <dimen name="notification_icon_circle_padding">4dp</dimen> + <!-- padding between the notification icon and the circle containing it + (2025 redesign version) --> + <dimen name="notification_2025_icon_circle_padding">8dp</dimen> + <!-- start margin of the icon circle in the notification view --> <dimen name="notification_icon_circle_start">16dp</dimen> @@ -803,6 +819,8 @@ <dimen name="notification_right_icon_big_margin_top">16dp</dimen> <!-- The size of the left icon --> <dimen name="notification_left_icon_size">@dimen/notification_icon_circle_size</dimen> + <!-- The size of the left icon (2025 redesign version) --> + <dimen name="notification_2025_left_icon_size">@dimen/notification_2025_icon_circle_size</dimen> <!-- The left padding of the left icon --> <dimen name="notification_left_icon_start">@dimen/notification_icon_circle_start</dimen> <!-- The alpha of a disabled notification button --> @@ -820,13 +838,13 @@ <!-- The gap between segments in the notification progress bar --> <dimen name="notification_progress_segSeg_gap">2dp</dimen> <!-- The gap between a segment and a point in the notification progress bar --> - <dimen name="notification_progress_segPoint_gap">8dp</dimen> - <!-- The dash gap of the notification progress bar segments --> - <dimen name="notification_progress_segments_dash_gap">8dp</dimen> - <!-- The dash width of the notification progress bar segments --> - <dimen name="notification_progress_segments_dash_width">3dp</dimen> + <dimen name="notification_progress_segPoint_gap">4dp</dimen> <!-- The height of the notification progress bar segments --> <dimen name="notification_progress_segments_height">6dp</dimen> + <!-- The height of the notification progress bar faded segments --> + <dimen name="notification_progress_segments_faded_height">2dp</dimen> + <!-- The corner radius of the notification progress bar segments --> + <dimen name="notification_progress_segments_corner_radius">16dp</dimen> <!-- The radius of the notification progress bar points --> <dimen name="notification_progress_points_radius">6dp</dimen> <!-- The corner radius of the notification progress bar points drawn as rects --> diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml index b6436d0b30a5..b0b87d1dead6 100644 --- a/core/res/res/values/public-staging.xml +++ b/core/res/res/values/public-staging.xml @@ -131,6 +131,8 @@ <public name="alternateLauncherIcons"/> <!-- @FlaggedApi(android.content.pm.Flags.FLAG_CHANGE_LAUNCHER_BADGING) --> <public name="alternateLauncherLabels"/> + <!-- @FlaggedApi(android.content.pm.Flags.FLAG_APP_COMPAT_OPTION_16KB) --> + <public name="pageSizeCompat" /> </staging-public-group> <staging-public-group type="id" first-id="0x01b60000"> @@ -140,12 +142,39 @@ </staging-public-group> <staging-public-group type="string" first-id="0x01b40000"> + <!-- @FlaggedApi(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER) + @hide @SystemApi --> + <public name="config_systemDependencyInstaller" /> </staging-public-group> <staging-public-group type="dimen" first-id="0x01b30000"> </staging-public-group> <staging-public-group type="color" first-id="0x01b20000"> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_inverse_on_surface_light"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_inverse_primary_light"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_inverse_surface_light"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_scrim_light"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_shadow_light"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_surface_tint_light"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_inverse_on_surface_dark"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_inverse_primary_dark"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_inverse_surface_dark"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_scrim_dark"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_shadow_dark"/> + <!-- @FlaggedApi(android.os.Flags.FLAG_MATERIAL_COLORS_10_2024)--> + <public name="system_surface_tint_dark"/> </staging-public-group> <staging-public-group type="array" first-id="0x01b10000"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 9dd302784c2c..a2a19a23d431 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2389,6 +2389,8 @@ <java-symbol type="layout" name="notification_material_action" /> <java-symbol type="layout" name="notification_material_action_list" /> <java-symbol type="layout" name="notification_material_action_tombstone" /> + <java-symbol type="layout" name="notification_2025_template_collapsed_base" /> + <java-symbol type="layout" name="notification_2025_template_header" /> <java-symbol type="layout" name="notification_template_material_base" /> <java-symbol type="layout" name="notification_template_material_heads_up_base" /> <java-symbol type="layout" name="notification_template_material_compact_heads_up_base" /> @@ -3140,9 +3142,12 @@ <!-- Gesture --> <java-symbol type="integer" name="config_cameraLaunchGestureSensorType" /> <java-symbol type="string" name="config_cameraLaunchGestureSensorStringType" /> - <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" /> <java-symbol type="integer" name="config_cameraLiftTriggerSensorType" /> <java-symbol type="string" name="config_cameraLiftTriggerSensorStringType" /> + <java-symbol type="bool" name="config_doubleTapPowerGestureEnabled" /> + <java-symbol type="bool" name="config_cameraDoubleTapPowerGestureEnabled" /> + <java-symbol type="bool" name="config_walletDoubleTapPowerGestureEnabled" /> + <java-symbol type="integer" name="config_defaultDoubleTapPowerGestureAction" /> <java-symbol type="bool" name="config_emergencyGestureEnabled" /> <java-symbol type="bool" name="config_defaultEmergencyGestureEnabled" /> <java-symbol type="bool" name="config_defaultEmergencyGestureSoundEnabled" /> @@ -3876,9 +3881,9 @@ <java-symbol type="dimen" name="notification_progress_tracker_height" /> <java-symbol type="dimen" name="notification_progress_segSeg_gap" /> <java-symbol type="dimen" name="notification_progress_segPoint_gap" /> - <java-symbol type="dimen" name="notification_progress_segments_dash_gap" /> - <java-symbol type="dimen" name="notification_progress_segments_dash_width" /> <java-symbol type="dimen" name="notification_progress_segments_height" /> + <java-symbol type="dimen" name="notification_progress_segments_faded_height" /> + <java-symbol type="dimen" name="notification_progress_segments_corner_radius" /> <java-symbol type="dimen" name="notification_progress_points_radius" /> <java-symbol type="dimen" name="notification_progress_points_corner_radius" /> <java-symbol type="dimen" name="notification_progress_points_inset" /> @@ -5311,73 +5316,91 @@ <java-symbol type="integer" name="config_aggregatedPowerStatsSpanDuration" /> <java-symbol type="integer" name="config_accumulatedBatteryUsageStatsSpanSize" /> - <java-symbol name="materialColorOnSecondaryFixedVariant" type="attr"/> - <java-symbol name="materialColorOnTertiaryFixedVariant" type="attr"/> - <java-symbol name="materialColorSurfaceContainerLowest" type="attr"/> - <java-symbol name="materialColorOnPrimaryFixedVariant" type="attr"/> - <java-symbol name="materialColorOnSecondaryContainer" type="attr"/> - <java-symbol name="materialColorOnTertiaryContainer" type="attr"/> - <java-symbol name="materialColorSurfaceContainerLow" type="attr"/> - <java-symbol name="materialColorOnPrimaryContainer" type="attr"/> - <java-symbol name="materialColorSecondaryFixedDim" type="attr"/> - <java-symbol name="materialColorOnErrorContainer" type="attr"/> - <java-symbol name="materialColorOnSecondaryFixed" type="attr"/> - <java-symbol name="materialColorOnSurfaceInverse" type="attr"/> - <java-symbol name="materialColorTertiaryFixedDim" type="attr"/> - <java-symbol name="materialColorOnTertiaryFixed" type="attr"/> - <java-symbol name="materialColorPrimaryFixedDim" type="attr"/> - <java-symbol name="materialColorSecondaryContainer" type="attr"/> - <java-symbol name="materialColorErrorContainer" type="attr"/> - <java-symbol name="materialColorOnPrimaryFixed" type="attr"/> - <java-symbol name="materialColorPrimaryInverse" type="attr"/> - <java-symbol name="materialColorSecondaryFixed" type="attr"/> - <java-symbol name="materialColorSurfaceInverse" type="attr"/> - <java-symbol name="materialColorSurfaceVariant" type="attr"/> - <java-symbol name="materialColorTertiaryContainer" type="attr"/> - <java-symbol name="materialColorTertiaryFixed" type="attr"/> - <java-symbol name="materialColorPrimaryContainer" type="attr"/> - <java-symbol name="materialColorOnBackground" type="attr"/> - <java-symbol name="materialColorPrimaryFixed" type="attr"/> - <java-symbol name="materialColorOnSecondary" type="attr"/> - <java-symbol name="materialColorOnTertiary" type="attr"/> - <java-symbol name="materialColorSurfaceDim" type="attr"/> - <java-symbol name="materialColorSurfaceBright" type="attr"/> - <java-symbol name="materialColorOnError" type="attr"/> - <java-symbol name="materialColorSurface" type="attr"/> - <java-symbol name="materialColorSurfaceContainerHigh" type="attr"/> - <java-symbol name="materialColorSurfaceContainerHighest" type="attr"/> - <java-symbol name="materialColorOnSurfaceVariant" type="attr"/> - <java-symbol name="materialColorOutline" type="attr"/> - <java-symbol name="materialColorOutlineVariant" type="attr"/> - <java-symbol name="materialColorOnPrimary" type="attr"/> - <java-symbol name="materialColorOnSurface" type="attr"/> - <java-symbol name="materialColorSurfaceContainer" type="attr"/> - <java-symbol name="materialColorPrimary" type="attr"/> - <java-symbol name="materialColorSecondary" type="attr"/> - <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="customColorThemeNotif" 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"/> + <!--Dynamic Tokens--> + <java-symbol type="attr" name="materialColorBackground"/> + <java-symbol type="attr" name="materialColorControlActivated"/> + <java-symbol type="attr" name="materialColorControlHighlight"/> + <java-symbol type="attr" name="materialColorControlNormal"/> + <java-symbol type="attr" name="materialColorError"/> + <java-symbol type="attr" name="materialColorErrorContainer"/> + <java-symbol type="attr" name="materialColorInverseOnSurface"/> + <java-symbol type="attr" name="materialColorInversePrimary"/> + <java-symbol type="attr" name="materialColorInverseSurface"/> + <java-symbol type="attr" name="materialColorOnBackground"/> + <java-symbol type="attr" name="materialColorOnError"/> + <java-symbol type="attr" name="materialColorOnErrorContainer"/> + <java-symbol type="attr" name="materialColorOnPrimary"/> + <java-symbol type="attr" name="materialColorOnPrimaryContainer"/> + <java-symbol type="attr" name="materialColorOnSecondary"/> + <java-symbol type="attr" name="materialColorOnSecondaryContainer"/> + <java-symbol type="attr" name="materialColorOnSurface"/> + <java-symbol type="attr" name="materialColorOnSurfaceVariant"/> + <java-symbol type="attr" name="materialColorOnTertiary"/> + <java-symbol type="attr" name="materialColorOnTertiaryContainer"/> + <java-symbol type="attr" name="materialColorOutline"/> + <java-symbol type="attr" name="materialColorOutlineVariant"/> + <java-symbol type="attr" name="materialColorPaletteKeyColorNeutral"/> + <java-symbol type="attr" name="materialColorPaletteKeyColorNeutralVariant"/> + <java-symbol type="attr" name="materialColorPaletteKeyColorPrimary"/> + <java-symbol type="attr" name="materialColorPaletteKeyColorSecondary"/> + <java-symbol type="attr" name="materialColorPaletteKeyColorTertiary"/> + <java-symbol type="attr" name="materialColorPrimary"/> + <java-symbol type="attr" name="materialColorPrimaryContainer"/> + <java-symbol type="attr" name="materialColorScrim"/> + <java-symbol type="attr" name="materialColorSecondary"/> + <java-symbol type="attr" name="materialColorSecondaryContainer"/> + <java-symbol type="attr" name="materialColorShadow"/> + <java-symbol type="attr" name="materialColorSurface"/> + <java-symbol type="attr" name="materialColorSurfaceBright"/> + <java-symbol type="attr" name="materialColorSurfaceContainer"/> + <java-symbol type="attr" name="materialColorSurfaceContainerHigh"/> + <java-symbol type="attr" name="materialColorSurfaceContainerHighest"/> + <java-symbol type="attr" name="materialColorSurfaceContainerLow"/> + <java-symbol type="attr" name="materialColorSurfaceContainerLowest"/> + <java-symbol type="attr" name="materialColorSurfaceDim"/> + <java-symbol type="attr" name="materialColorSurfaceTint"/> + <java-symbol type="attr" name="materialColorSurfaceVariant"/> + <java-symbol type="attr" name="materialColorTertiary"/> + <java-symbol type="attr" name="materialColorTertiaryContainer"/> + <java-symbol type="attr" name="materialColorTextHintInverse"/> + <java-symbol type="attr" name="materialColorTextPrimaryInverse"/> + <java-symbol type="attr" name="materialColorTextPrimaryInverseDisableOnly"/> + <java-symbol type="attr" name="materialColorTextSecondaryAndTertiaryInverse"/> + <java-symbol type="attr" name="materialColorTextSecondaryAndTertiaryInverseDisabled"/> + <java-symbol type="attr" name="materialColorOnPrimaryFixed"/> + <java-symbol type="attr" name="materialColorOnPrimaryFixedVariant"/> + <java-symbol type="attr" name="materialColorOnSecondaryFixed"/> + <java-symbol type="attr" name="materialColorOnSecondaryFixedVariant"/> + <java-symbol type="attr" name="materialColorOnTertiaryFixed"/> + <java-symbol type="attr" name="materialColorOnTertiaryFixedVariant"/> + <java-symbol type="attr" name="materialColorPrimaryFixed"/> + <java-symbol type="attr" name="materialColorPrimaryFixedDim"/> + <java-symbol type="attr" name="materialColorSecondaryFixed"/> + <java-symbol type="attr" name="materialColorSecondaryFixedDim"/> + <java-symbol type="attr" name="materialColorTertiaryFixed"/> + <java-symbol type="attr" name="materialColorTertiaryFixedDim"/> + <java-symbol type="attr" name="customColorBrandA"/> + <java-symbol type="attr" name="customColorBrandB"/> + <java-symbol type="attr" name="customColorBrandC"/> + <java-symbol type="attr" name="customColorBrandD"/> + <java-symbol type="attr" name="customColorClockHour"/> + <java-symbol type="attr" name="customColorClockMinute"/> + <java-symbol type="attr" name="customColorClockSecond"/> + <java-symbol type="attr" name="customColorOnShadeActive"/> + <java-symbol type="attr" name="customColorOnShadeActiveVariant"/> + <java-symbol type="attr" name="customColorOnShadeInactive"/> + <java-symbol type="attr" name="customColorOnShadeInactiveVariant"/> + <java-symbol type="attr" name="customColorOnThemeApp"/> + <java-symbol type="attr" name="customColorOverviewBackground"/> + <java-symbol type="attr" name="customColorShadeActive"/> + <java-symbol type="attr" name="customColorShadeDisabled"/> + <java-symbol type="attr" name="customColorShadeInactive"/> + <java-symbol type="attr" name="customColorThemeApp"/> + <java-symbol type="attr" name="customColorThemeAppRing"/> + <java-symbol type="attr" name="customColorThemeNotif"/> + <java-symbol type="attr" name="customColorUnderSurface"/> + <java-symbol type="attr" name="customColorWeatherTemp"/> + <java-symbol type="attr" name="customColorWidgetBackground"/> <java-symbol name="system_widget_background_light" type="color"/> <java-symbol name="system_clock_hour_light" type="color"/> @@ -5679,8 +5702,8 @@ <java-symbol type="string" name="identity_check_settings_action" /> <java-symbol type="string" name="identity_check_settings_package_name" /> - <!-- Forensic backup transport --> - <java-symbol type="string" name="config_forensicBackupTransport" /> + <!-- Forensic event transport --> + <java-symbol type="string" name="config_forensicEventTransport" /> <!-- Fingerprint screen off unlock config --> <java-symbol type="bool" name="config_screen_off_udfps_enabled" /> diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml index 352c3904406c..d8346d87f624 100644 --- a/core/res/res/values/themes_device_defaults.xml +++ b/core/res/res/values/themes_device_defaults.xml @@ -239,73 +239,90 @@ easier. <item name="colorForeground">@color/foreground_device_default_dark</item> <item name="colorForegroundInverse">@color/foreground_device_default_light</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="Theme.DeviceDefault" parent="Theme.DeviceDefaultBase" /> @@ -357,73 +374,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme @@ -474,73 +508,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and @@ -593,73 +644,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent @@ -711,73 +779,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be @@ -837,73 +922,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a @@ -954,73 +1056,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar --> @@ -1070,73 +1189,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width @@ -1187,73 +1323,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. --> @@ -1320,73 +1473,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for a window without an action bar that will be displayed either @@ -1438,73 +1608,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for a presentation window on a secondary display. --> @@ -1554,73 +1741,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for panel windows. This removes all extraneous window @@ -1672,73 +1876,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear @@ -1789,73 +2010,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear @@ -1906,73 +2144,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- DeviceDefault style for input methods, which is used by the @@ -2023,73 +2278,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault style for input methods, which is used by the @@ -2140,73 +2412,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert"> @@ -2257,73 +2546,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Theme for the dialog shown when an app crashes or ANRs. --> @@ -2379,73 +2685,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame"> @@ -2494,73 +2817,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style --> @@ -2747,73 +3087,90 @@ easier. <item name="colorPopupBackground">?attr/colorBackgroundFloating</item> <item name="panelColorBackground">?attr/colorBackgroundFloating</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an @@ -2864,73 +3221,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar --> @@ -2980,73 +3354,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar. @@ -3097,73 +3488,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar @@ -3216,73 +3624,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent @@ -3334,73 +3759,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be @@ -3458,73 +3900,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a @@ -3578,73 +4037,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar --> @@ -3697,73 +4173,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum @@ -3817,73 +4310,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. --> @@ -3918,73 +4428,90 @@ easier. <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. --> @@ -4019,73 +4546,90 @@ easier. <item name="colorForeground">@color/foreground_device_default_light</item> <item name="colorForegroundInverse">@color/foreground_device_default_dark</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller @@ -4139,73 +4683,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault light theme for a window without an action bar that will be displayed either @@ -4260,73 +4821,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault light theme for a presentation window on a secondary display. --> @@ -4379,73 +4957,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault light theme for panel windows. This removes all extraneous window @@ -4497,73 +5092,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert"> @@ -4614,73 +5226,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Dialog.Alert.DayNight" parent="Theme.DeviceDefault.Light.Dialog.Alert" /> @@ -4731,73 +5360,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice"> @@ -4846,73 +5492,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- DeviceDefault theme for a window that should look like the Settings app. --> @@ -4968,74 +5631,90 @@ easier. <item name="colorListDivider">@color/list_divider_color_light</item> <item name="opacityListDivider">@color/list_divider_opacity_device_default_light</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.SystemUI" parent="Theme.DeviceDefault.Light"> @@ -5072,74 +5751,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.SystemUI.Dialog" parent="Theme.DeviceDefault.Light.Dialog"> @@ -5168,74 +5863,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar --> @@ -5286,73 +5997,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="Theme.DeviceDefault.Settings.DialogBase" parent="Theme.Material.Light.BaseDialog"> @@ -5387,73 +6115,90 @@ easier. <!-- Dialog attributes --> <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Settings.DialogBase"> @@ -5528,73 +6273,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert"> @@ -5647,73 +6409,90 @@ easier. <!-- Toolbar attributes --> <item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" /> @@ -5792,73 +6571,90 @@ easier. <item name="colorAccentSecondary">@color/system_secondary_dark</item> <item name="colorAccentTertiary">@color/system_tertiary_dark</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="ThemeOverlay.DeviceDefault.Accent.Light"> @@ -5867,73 +6663,90 @@ easier. <item name="colorAccentSecondary">@color/system_secondary_dark</item> <item name="colorAccentTertiary">@color/system_tertiary_dark</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <!-- Theme overlay that replaces colorAccent with the colorAccent from {@link #Theme_DeviceDefault_DayNight}. --> @@ -5946,73 +6759,90 @@ easier. <item name="colorAccentSecondary">@color/system_secondary_dark</item> <item name="colorAccentTertiary">@color/system_tertiary_dark</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_background_dark</item> </style> <style name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" parent="Theme.DeviceDefault.NoActionBar.Fullscreen"> @@ -6021,73 +6851,90 @@ easier. <item name="layout_gravity">center</item> <item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_dark</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorBackground">@color/system_background_light</item> + <item name="materialColorControlActivated">@color/system_control_activated_light</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_light</item> + <item name="materialColorControlNormal">@color/system_control_normal_light</item> + <item name="materialColorError">@color/system_error_light</item> <item name="materialColorErrorContainer">@color/system_error_container_light</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_dark</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_dark</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_light</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_light</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_light</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_light</item> <item name="materialColorOnBackground">@color/system_on_background_light</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> <item name="materialColorOnError">@color/system_on_error_light</item> - <item name="materialColorSurface">@color/system_surface_light</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_light</item> + <item name="materialColorOnPrimary">@color/system_on_primary_light</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_light</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_light</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_light</item> + <item name="materialColorOnSurface">@color/system_on_surface_light</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_light</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_light</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_light</item> <item name="materialColorOutline">@color/system_outline_light</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_light</item> - <item name="materialColorOnPrimary">@color/system_on_primary_light</item> - <item name="materialColorOnSurface">@color/system_on_surface_light</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_light</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_light</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_light</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_light</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_light</item> <item name="materialColorPrimary">@color/system_primary_light</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_light</item> + <item name="materialColorScrim">@color/system_scrim_light</item> <item name="materialColorSecondary">@color/system_secondary_light</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_light</item> + <item name="materialColorShadow">@color/system_shadow_light</item> + <item name="materialColorSurface">@color/system_surface_light</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_light</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_light</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_light</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_light</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_light</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_light</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_light</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_light</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_light</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_light</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_light</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_light</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_light</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_light</item> <item name="customColorOverviewBackground">@color/system_overview_background_light</item> + <item name="customColorShadeActive">@color/system_shade_active_light</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_light</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_light</item> + <item name="customColorThemeApp">@color/system_theme_app_light</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_light</item> + <item name="customColorThemeNotif">@color/system_theme_notif_light</item> + <item name="customColorUnderSurface">@color/system_under_surface_light</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_light</item> + <item name="customColorWidgetBackground">@color/system_widget_background_light</item> </style> <style name="Theme.DeviceDefault.Notification" parent="@style/Theme.Material.Notification"> @@ -6107,73 +6954,90 @@ easier. <item name="textColorPrimary">@color/system_neutral1_900</item> <item name="textColorSecondary">@color/system_neutral2_700</item> - <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> - <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> - <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> - <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> - <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> - <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> - <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> - <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> - <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> - <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> - <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> - <item name="materialColorOnSurfaceInverse">@color/system_on_surface_light</item> - <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</item> - <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> - <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> - <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorBackground">@color/system_background_dark</item> + <item name="materialColorControlActivated">@color/system_control_activated_dark</item> + <item name="materialColorControlHighlight">@color/system_control_highlight_dark</item> + <item name="materialColorControlNormal">@color/system_control_normal_dark</item> + <item name="materialColorError">@color/system_error_dark</item> <item name="materialColorErrorContainer">@color/system_error_container_dark</item> - <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> - <item name="materialColorPrimaryInverse">@color/system_primary_light</item> - <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> - <item name="materialColorSurfaceInverse">@color/system_surface_light</item> - <item name="materialColorSurfaceVariant">@color/system_surface_variant_dark</item> - <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> - <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> - <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorInverseOnSurface">@color/system_inverse_on_surface_dark</item> + <item name="materialColorInversePrimary">@color/system_inverse_primary_dark</item> + <item name="materialColorInverseSurface">@color/system_inverse_surface_dark</item> <item name="materialColorOnBackground">@color/system_on_background_dark</item> - <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> - <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> - <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> - <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> - <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> <item name="materialColorOnError">@color/system_on_error_dark</item> - <item name="materialColorSurface">@color/system_surface_dark</item> - <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> - <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorOnErrorContainer">@color/system_on_error_container_dark</item> + <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> + <item name="materialColorOnPrimaryContainer">@color/system_on_primary_container_dark</item> + <item name="materialColorOnSecondary">@color/system_on_secondary_dark</item> + <item name="materialColorOnSecondaryContainer">@color/system_on_secondary_container_dark</item> + <item name="materialColorOnSurface">@color/system_on_surface_dark</item> <item name="materialColorOnSurfaceVariant">@color/system_on_surface_variant_dark</item> + <item name="materialColorOnTertiary">@color/system_on_tertiary_dark</item> + <item name="materialColorOnTertiaryContainer">@color/system_on_tertiary_container_dark</item> <item name="materialColorOutline">@color/system_outline_dark</item> <item name="materialColorOutlineVariant">@color/system_outline_variant_dark</item> - <item name="materialColorOnPrimary">@color/system_on_primary_dark</item> - <item name="materialColorOnSurface">@color/system_on_surface_dark</item> - <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorPaletteKeyColorNeutral">@color/system_palette_key_color_neutral_dark</item> + <item name="materialColorPaletteKeyColorNeutralVariant">@color/system_palette_key_color_neutral_variant_dark</item> + <item name="materialColorPaletteKeyColorPrimary">@color/system_palette_key_color_primary_dark</item> + <item name="materialColorPaletteKeyColorSecondary">@color/system_palette_key_color_secondary_dark</item> + <item name="materialColorPaletteKeyColorTertiary">@color/system_palette_key_color_tertiary_dark</item> <item name="materialColorPrimary">@color/system_primary_dark</item> + <item name="materialColorPrimaryContainer">@color/system_primary_container_dark</item> + <item name="materialColorScrim">@color/system_scrim_dark</item> <item name="materialColorSecondary">@color/system_secondary_dark</item> + <item name="materialColorSecondaryContainer">@color/system_secondary_container_dark</item> + <item name="materialColorShadow">@color/system_shadow_dark</item> + <item name="materialColorSurface">@color/system_surface_dark</item> + <item name="materialColorSurfaceBright">@color/system_surface_bright_dark</item> + <item name="materialColorSurfaceContainer">@color/system_surface_container_dark</item> + <item name="materialColorSurfaceContainerHigh">@color/system_surface_container_high_dark</item> + <item name="materialColorSurfaceContainerHighest">@color/system_surface_container_highest_dark</item> + <item name="materialColorSurfaceContainerLow">@color/system_surface_container_low_dark</item> + <item name="materialColorSurfaceContainerLowest">@color/system_surface_container_lowest_dark</item> + <item name="materialColorSurfaceDim">@color/system_surface_dim_dark</item> + <item name="materialColorSurfaceTint">@color/system_surface_tint_dark</item> + <item name="materialColorSurfaceVariant">@color/system_surface_variant_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="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="materialColorTertiaryContainer">@color/system_tertiary_container_dark</item> + <item name="materialColorTextHintInverse">@color/system_text_hint_inverse_dark</item> + <item name="materialColorTextPrimaryInverse">@color/system_text_primary_inverse_dark</item> + <item name="materialColorTextPrimaryInverseDisableOnly">@color/system_text_primary_inverse_disable_only_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverse">@color/system_text_secondary_and_tertiary_inverse_dark</item> + <item name="materialColorTextSecondaryAndTertiaryInverseDisabled">@color/system_text_secondary_and_tertiary_inverse_disabled_dark</item> + <item name="materialColorOnPrimaryFixed">@color/system_on_primary_fixed</item> + <item name="materialColorOnPrimaryFixedVariant">@color/system_on_primary_fixed_variant</item> + <item name="materialColorOnSecondaryFixed">@color/system_on_secondary_fixed</item> + <item name="materialColorOnSecondaryFixedVariant">@color/system_on_secondary_fixed_variant</item> + <item name="materialColorOnTertiaryFixed">@color/system_on_tertiary_fixed</item> + <item name="materialColorOnTertiaryFixedVariant">@color/system_on_tertiary_fixed_variant</item> + <item name="materialColorPrimaryFixed">@color/system_primary_fixed</item> + <item name="materialColorPrimaryFixedDim">@color/system_primary_fixed_dim</item> + <item name="materialColorSecondaryFixed">@color/system_secondary_fixed</item> + <item name="materialColorSecondaryFixedDim">@color/system_secondary_fixed_dim</item> + <item name="materialColorTertiaryFixed">@color/system_tertiary_fixed</item> + <item name="materialColorTertiaryFixedDim">@color/system_tertiary_fixed_dim</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="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="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="customColorOnThemeApp">@color/system_on_theme_app_dark</item> <item name="customColorOverviewBackground">@color/system_overview_background_dark</item> + <item name="customColorShadeActive">@color/system_shade_active_dark</item> + <item name="customColorShadeDisabled">@color/system_shade_disabled_dark</item> + <item name="customColorShadeInactive">@color/system_shade_inactive_dark</item> + <item name="customColorThemeApp">@color/system_theme_app_dark</item> + <item name="customColorThemeAppRing">@color/system_theme_app_ring_dark</item> + <item name="customColorThemeNotif">@color/system_theme_notif_dark</item> + <item name="customColorUnderSurface">@color/system_under_surface_dark</item> + <item name="customColorWeatherTemp">@color/system_weather_temp_dark</item> + <item name="customColorWidgetBackground">@color/system_widget_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/res/res/xml/bookmarks.xml b/core/res/res/xml/bookmarks.xml index 22d02262c388..e735784ee5bb 100644 --- a/core/res/res/xml/bookmarks.xml +++ b/core/res/res/xml/bookmarks.xml @@ -31,29 +31,37 @@ 'u': Calculator 'y': YouTube --> -<bookmarks> +<bookmarks xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <bookmark role="android.app.role.BROWSER" - shortcut="b" /> + androidprv:keycode="KEYCODE_B" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CONTACTS" - shortcut="c" /> + androidprv:keycode="KEYCODE_C" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_EMAIL" - shortcut="e" /> + androidprv:keycode="KEYCODE_E" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CALENDAR" - shortcut="k" /> + androidprv:keycode="KEYCODE_K" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_MAPS" - shortcut="m" /> + androidprv:keycode="KEYCODE_M" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_MUSIC" - shortcut="p" /> + androidprv:keycode="KEYCODE_P" + androidprv:modifierState="META" /> <bookmark role="android.app.role.SMS" - shortcut="s" /> + androidprv:keycode="KEYCODE_S" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CALCULATOR" - shortcut="u" /> + androidprv:keycode="KEYCODE_U" + androidprv:modifierState="META" /> </bookmarks> diff --git a/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java index 9dd196daf412..f62d420510c3 100644 --- a/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java +++ b/core/tests/InputMethodCoreTests/src/android/view/inputmethod/EditorInfoTest.java @@ -507,7 +507,8 @@ public class EditorInfoTest { + "prefix: supportedHandwritingGestureTypes=(none)\n" + "prefix: supportedHandwritingGesturePreviewTypes=(none)\n" + "prefix: isStylusHandwritingEnabled=false\n" - + "prefix: contentMimeTypes=null\n"); + + "prefix: contentMimeTypes=null\n" + + "prefix: writingToolsEnabled=true\n"); } @Test @@ -539,6 +540,7 @@ public class EditorInfoTest { info.hintLocales = LocaleList.forLanguageTags("en,es,zh"); info.contentMimeTypes = new String[] {"image/png"}; info.targetInputMethodUser = UserHandle.of(10); + info.setWritingToolsEnabled(false); final StringBuilder sb = new StringBuilder(); info.dump(new StringBuilderPrinter(sb), "prefix2: "); assertThat(sb.toString()).isEqualTo( @@ -555,7 +557,8 @@ public class EditorInfoTest { + "prefix2: supportedHandwritingGesturePreviewTypes=SELECT\n" + "prefix2: isStylusHandwritingEnabled=" + isStylusHandwritingEnabled + "\n" + "prefix2: contentMimeTypes=[image/png]\n" - + "prefix2: targetInputMethodUserId=10\n"); + + "prefix2: targetInputMethodUserId=10\n" + + "prefix2: writingToolsEnabled=false\n"); } @Test @@ -576,7 +579,8 @@ public class EditorInfoTest { + "prefix: supportedHandwritingGestureTypes=(none)\n" + "prefix: supportedHandwritingGesturePreviewTypes=(none)\n" + "prefix: isStylusHandwritingEnabled=false\n" - + "prefix: contentMimeTypes=null\n"); + + "prefix: contentMimeTypes=null\n" + + "prefix: writingToolsEnabled=true\n"); } @Test @@ -621,4 +625,9 @@ public class EditorInfoTest { infoCopy.extras.putString("testKey2", "testValue"); assertFalse(TEST_EDITOR_INFO.kindofEquals(infoCopy)); } + + @Test + public void testWritingToolsEnabledbyDefault() { + assertTrue(TEST_EDITOR_INFO.isWritingToolsEnabled()); + } } diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java index a2598f69e031..2fc72e1d3994 100644 --- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java +++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java @@ -16,6 +16,7 @@ package android.app; +import static android.app.Flags.FLAG_PIC_CACHE_NULLS; import static android.app.Flags.FLAG_PIC_ISOLATE_CACHE_BY_UID; import static android.app.PropertyInvalidatedCache.NONCE_UNSET; import static android.app.PropertyInvalidatedCache.MODULE_BLUETOOTH; @@ -229,7 +230,12 @@ public class PropertyInvalidatedCacheTests { @Override public String apply(Integer qv) { mRecomputeCount += 1; - return "foo" + qv.toString(); + // Special case for testing caches of nulls. Integers in the range 30-40 return null. + if (qv >= 30 && qv < 40) { + return null; + } else { + return "foo" + qv.toString(); + } } int getRecomputeCount() { @@ -643,4 +649,35 @@ public class PropertyInvalidatedCacheTests { Binder.restoreCallingWorkSource(token); } } + + @RequiresFlagsEnabled(FLAG_PIC_CACHE_NULLS) + @Test + public void testCachingNulls() { + TestCache cache = new TestCache(new Args(MODULE_TEST) + .maxEntries(4).api("testCachingNulls").cacheNulls(true), + new TestQuery()); + cache.invalidateCache(); + assertEquals("foo1", cache.query(1)); + assertEquals("foo2", cache.query(2)); + assertEquals(null, cache.query(30)); + assertEquals(3, cache.getRecomputeCount()); + assertEquals("foo1", cache.query(1)); + assertEquals("foo2", cache.query(2)); + assertEquals(null, cache.query(30)); + assertEquals(3, cache.getRecomputeCount()); + + cache = new TestCache(new Args(MODULE_TEST) + .maxEntries(4).api("testCachingNulls").cacheNulls(false), + new TestQuery()); + cache.invalidateCache(); + assertEquals("foo1", cache.query(1)); + assertEquals("foo2", cache.query(2)); + assertEquals(null, cache.query(30)); + assertEquals(3, cache.getRecomputeCount()); + assertEquals("foo1", cache.query(1)); + assertEquals("foo2", cache.query(2)); + assertEquals(null, cache.query(30)); + // The recompute is 4 because nulls were not cached. + assertEquals(4, cache.getRecomputeCount()); + } } diff --git a/core/tests/coretests/src/android/content/pm/SharedLibraryInfoTest.java b/core/tests/coretests/src/android/content/pm/SharedLibraryInfoTest.java new file mode 100644 index 000000000000..df5cd4e95418 --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/SharedLibraryInfoTest.java @@ -0,0 +1,69 @@ +/* + * 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 android.content.pm; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.Parcel; +import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; + +import com.google.common.collect.ImmutableList; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.List; + +@Presubmit +@RunWith(JUnit4.class) +public final class SharedLibraryInfoTest { + + @Rule + public final CheckFlagsRule checkFlagsRule = + DeviceFlagsValueProvider.createCheckFlagsRule(); + + private static final String LIBRARY_NAME = "name"; + private static final long VERSION_MAJOR = 1L; + private static final List<String> CERT_DIGESTS = ImmutableList.of("digest1", "digest2"); + + @Test + @RequiresFlagsEnabled(Flags.FLAG_SDK_DEPENDENCY_INSTALLER) + public void sharedLibraryInfo_serializedAndDeserialized_retainsCertDigestInfo() { + SharedLibraryInfo toParcel = new SharedLibraryInfo(LIBRARY_NAME, VERSION_MAJOR, + SharedLibraryInfo.TYPE_SDK_PACKAGE, CERT_DIGESTS); + + SharedLibraryInfo fromParcel = parcelAndUnparcel(toParcel); + + assertThat(fromParcel.getCertDigests().size()).isEqualTo(toParcel.getCertDigests().size()); + assertThat(fromParcel.getCertDigests().get(0)).isEqualTo(toParcel.getCertDigests().get(0)); + assertThat(fromParcel.getCertDigests().get(1)).isEqualTo(toParcel.getCertDigests().get(1)); + } + + private SharedLibraryInfo parcelAndUnparcel(SharedLibraryInfo sharedLibraryInfo) { + Parcel parcel = Parcel.obtain(); + parcel.setDataPosition(0); + sharedLibraryInfo.writeToParcel(parcel, /* flags= */0); + + parcel.setDataPosition(0); + return SharedLibraryInfo.CREATOR.createFromParcel(parcel); + } +} diff --git a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java index 0db49a72c51d..ecacdb2bde0b 100644 --- a/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java +++ b/core/tests/coretests/src/android/content/pm/parsing/ApkLiteParseUtilsTest.java @@ -33,6 +33,7 @@ import android.content.pm.parsing.result.ParseTypeImpl; import android.os.FileUtils; import android.os.ParcelFileDescriptor; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsEnabled; import android.util.ArraySet; import android.util.PackageUtils; @@ -61,6 +62,7 @@ import java.util.List; import java.util.Set; @Presubmit +@RequiresFlagsEnabled(android.content.pm.Flags.FLAG_SDK_DEPENDENCY_INSTALLER) public class ApkLiteParseUtilsTest { @Rule diff --git a/core/tests/coretests/src/android/os/OWNERS b/core/tests/coretests/src/android/os/OWNERS index 6149382d0800..4620cb8d8148 100644 --- a/core/tests/coretests/src/android/os/OWNERS +++ b/core/tests/coretests/src/android/os/OWNERS @@ -12,3 +12,6 @@ per-file PerformanceHintManagerTest.java = file:/ADPF_OWNERS # Caching per-file IpcDataCache* = file:/PERFORMANCE_OWNERS + +# RemoteCallbackList +per-file RemoteCallbackListTest.java = shayba@google.com diff --git a/core/tests/vibrator/src/android/os/VibrationEffectTest.java b/core/tests/vibrator/src/android/os/VibrationEffectTest.java index 1cd1190c4080..ccc5108abc19 100644 --- a/core/tests/vibrator/src/android/os/VibrationEffectTest.java +++ b/core/tests/vibrator/src/android/os/VibrationEffectTest.java @@ -414,10 +414,10 @@ public class VibrationEffectTest { @Test @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) - public void computeLegacyPattern_effectsViaStartWaveformEnvelope() { - // Effects created via startWaveformEnvelope are not expected to be converted to long[] + public void computeLegacyPattern_effectsViaWaveformEnvelopeBuilder() { + // Effects created via waveformEnvelopeBuilder are not expected to be converted to long[] // patterns, as they are not configured to always play with the default amplitude. - VibrationEffect effect = VibrationEffect.startWaveformEnvelope() + VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50) .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80) @@ -426,7 +426,8 @@ public class VibrationEffectTest { assertNull(effect.computeCreateWaveformOffOnTimingsOrNull()); - effect = VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 60) + effect = new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 60) .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50) .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80) @@ -644,7 +645,7 @@ public class VibrationEffectTest { @Test @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) public void testValidateWaveformEnvelopeBuilder() { - VibrationEffect.startWaveformEnvelope() + new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50) .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80) @@ -652,7 +653,8 @@ public class VibrationEffectTest { .build() .validate(); - VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30) + new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30) .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50) .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 80) @@ -661,13 +663,13 @@ public class VibrationEffectTest { .validate(); VibrationEffect.createRepeatingEffect( - /*preamble=*/ VibrationEffect.startWaveformEnvelope() + /*preamble=*/ new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 50) .build(), - /*repeatingEffect=*/ VibrationEffect.startWaveformEnvelope() + /*repeatingEffect=*/ new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .addControlPoint(/*amplitude=*/ 0.5f, /*frequencyHz=*/ 150f, @@ -676,7 +678,7 @@ public class VibrationEffectTest { ).validate(); VibrationEffect.createRepeatingEffect( - /*effect=*/ VibrationEffect.startWaveformEnvelope() + /*effect=*/ new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .addControlPoint(/*amplitude=*/ 0.5f, /*frequencyHz=*/ 150f, @@ -685,59 +687,70 @@ public class VibrationEffectTest { ).validate(); assertThrows(IllegalStateException.class, - () -> VibrationEffect.startWaveformEnvelope().build().validate()); + () -> new VibrationEffect.WaveformEnvelopeBuilder().build().validate()); assertThrows(IllegalArgumentException.class, - () -> VibrationEffect.startWaveformEnvelope() + () -> new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ -1.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .build() .validate()); assertThrows(IllegalArgumentException.class, - () -> VibrationEffect.startWaveformEnvelope() + () -> new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 1.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .build() .validate()); assertThrows(IllegalArgumentException.class, - () -> VibrationEffect.startWaveformEnvelope() + () -> new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 0f, /*timeMillis=*/ 20) .build() .validate()); assertThrows(IllegalArgumentException.class, - () -> VibrationEffect.startWaveformEnvelope() + () -> new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 0) .build() .validate()); assertThrows(IllegalStateException.class, - () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30) + () -> new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30) .build().validate()); assertThrows(IllegalArgumentException.class, - () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30) + () -> new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30) .addControlPoint(/*amplitude=*/ -1.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .build() .validate()); assertThrows(IllegalArgumentException.class, - () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30) + () -> new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30) .addControlPoint(/*amplitude=*/ 1.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .build() .validate()); assertThrows(IllegalArgumentException.class, - () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30) + () -> new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30) .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 0f, /*timeMillis=*/ 20) .build() .validate()); assertThrows(IllegalArgumentException.class, - () -> VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/30) + () -> new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30) .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 0) .build() .validate()); + assertThrows(IllegalArgumentException.class, + () -> new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 0) + .addControlPoint(/*amplitude=*/ 0.8f, /*frequencyHz=*/ 100f, + /*timeMillis=*/ 20) + .build().validate()); } @Test @@ -1381,14 +1394,15 @@ public class VibrationEffectTest { @Test @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) public void testIsHapticFeedbackCandidate_longEnvelopeEffects_notCandidates() { - assertFalse(VibrationEffect.startWaveformEnvelope() + assertFalse(new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 200) .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500) .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 800) .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400) .build() .isHapticFeedbackCandidate()); - assertFalse(VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 40) + assertFalse(new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 40) .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 200) .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500) .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 800) @@ -1413,13 +1427,14 @@ public class VibrationEffectTest { @Test @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) public void testIsHapticFeedbackCandidate_shortEnvelopeEffects_areCandidates() { - assertTrue(VibrationEffect.startWaveformEnvelope() + assertTrue(new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500) .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400) .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 100) .build() .isHapticFeedbackCandidate()); - assertTrue(VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30) + assertTrue(new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30) .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 500) .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 400) .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 100) diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 541ca602a386..fea7cb4b422c 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -93,6 +93,10 @@ applications that come with the platform <permission name="android.permission.INTERACT_ACROSS_USERS"/> </privapp-permissions> + <privapp-permissions package="com.android.media.quality"> + <permission name="android.permission.OBSERVE_PICTURE_PROFILES"/> + </privapp-permissions> + <privapp-permissions package="com.android.mtp"> <permission name="android.permission.ACCESS_MTP"/> <permission name="android.permission.MANAGE_USB"/> @@ -262,6 +266,8 @@ applications that come with the platform <!-- BLUETOOTH_PRIVILEGED is needed for test only --> <permission name="android.permission.BLUETOOTH_PRIVILEGED"/> <permission name="android.permission.BIND_APPWIDGET"/> + <!-- Needed for CTS tests only --> + <permission name="android.permission.OBSERVE_PICTURE_PROFILES"/> <permission name="android.permission.CHANGE_APP_IDLE_STATE"/> <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> <permission name="android.permission.CHANGE_CONFIGURATION"/> @@ -597,6 +603,9 @@ applications that come with the platform <!-- Permissions required for CTS test - SettingsPreferenceServiceClientTest --> <permission name="android.permission.READ_SYSTEM_PREFERENCES" /> <permission name="android.permission.WRITE_SYSTEM_PREFERENCES" /> + <!-- Permission required for CTS test - ForensicManagerTest --> + <permission name="android.permission.READ_FORENSIC_STATE" /> + <permission name="android.permission.MANAGE_FORENSIC_STATE" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/graphics/java/android/graphics/BlendMode.java b/graphics/java/android/graphics/BlendMode.java index 5c294aa72ce8..c6ae680d01bf 100644 --- a/graphics/java/android/graphics/BlendMode.java +++ b/graphics/java/android/graphics/BlendMode.java @@ -571,10 +571,10 @@ public enum BlendMode { } @NonNull - private final Xfermode mXfermode; + private final PorterDuffXfermode mXfermode; BlendMode(int mode) { - mXfermode = new Xfermode(); + mXfermode = new PorterDuffXfermode(); mXfermode.porterDuffMode = mode; } @@ -582,7 +582,7 @@ public enum BlendMode { * @hide */ @NonNull - public Xfermode getXfermode() { + public PorterDuffXfermode getXfermode() { return mXfermode; } } diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java index 977aeaa2f4d9..e7145686247e 100644 --- a/graphics/java/android/graphics/ComposeShader.java +++ b/graphics/java/android/graphics/ComposeShader.java @@ -40,9 +40,12 @@ public class ComposeShader extends Shader { * @param mode The mode that combines the colors from the two shaders. If mode * is null, then SRC_OVER is assumed. */ + //TODO(358126864): allow a ComposeShader to accept a RuntimeXfermode @Deprecated public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull Xfermode mode) { - this(shaderA, shaderB, mode.porterDuffMode); + this(shaderA, shaderB, + mode instanceof PorterDuffXfermode ? ((PorterDuffXfermode) mode).porterDuffMode + : BlendMode.SRC_OVER.getXfermode().porterDuffMode); } /** diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 56bb0f0d12d5..9bf4d65e1865 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -71,6 +71,7 @@ public class Paint { private long mNativePaint; private long mNativeShader; private long mNativeColorFilter; + private long mNativeXfermode; // Use a Holder to allow static initialization of Paint in the boot image. private static class NoImagePreloadHolder { @@ -735,6 +736,7 @@ public class Paint { mPathEffect = null; mShader = null; mNativeShader = 0; + mNativeXfermode = 0; mTypeface = null; mXfermode = null; @@ -780,6 +782,7 @@ public class Paint { mNativeShader = paint.mNativeShader; mTypeface = paint.mTypeface; mXfermode = paint.mXfermode; + mNativeXfermode = paint.mNativeXfermode; mHasCompatScaling = paint.mHasCompatScaling; mCompatScaling = paint.mCompatScaling; @@ -815,7 +818,7 @@ public class Paint { * * Note: Although this method is |synchronized|, this is simply so it * is not thread-hostile to multiple threads calling this method. It - * is still unsafe to attempt to change the Shader/ColorFilter while + * is still unsafe to attempt to change the Shader/ColorFilter/Xfermode while * another thread attempts to access the native object. * * @hide @@ -833,6 +836,15 @@ public class Paint { mNativeColorFilter = newNativeColorFilter; nSetColorFilter(mNativePaint, mNativeColorFilter); } + if (com.android.graphics.hwui.flags.Flags.runtimeColorFiltersBlenders()) { + if (mXfermode instanceof RuntimeXfermode) { + long newNativeXfermode = ((RuntimeXfermode) mXfermode).createNativeInstance(); + if (newNativeXfermode != mNativeXfermode) { + mNativeXfermode = newNativeXfermode; + nSetXfermode(mNativePaint, mNativeXfermode); + } + } + } return mNativePaint; } @@ -1427,16 +1439,17 @@ public class Paint { } /** - * Get the paint's blend mode object. + * Get the paint's blend mode object. Will return null if there is a Xfermode applied that + * cannot be represented by a blend mode (i.e. a custom {@code RuntimeXfermode} * * @return the paint's blend mode (or null) */ @Nullable public BlendMode getBlendMode() { - if (mXfermode == null) { + if (mXfermode == null || !(mXfermode instanceof PorterDuffXfermode)) { return null; } else { - return BlendMode.fromValue(mXfermode.porterDuffMode); + return BlendMode.fromValue(((PorterDuffXfermode) mXfermode).porterDuffMode); } } @@ -1459,8 +1472,17 @@ public class Paint { @Nullable private Xfermode installXfermode(Xfermode xfermode) { - int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT; - int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT; + if (com.android.graphics.hwui.flags.Flags.runtimeColorFiltersBlenders()) { + if (xfermode instanceof RuntimeXfermode) { + mXfermode = xfermode; + nSetXfermode(mNativePaint, ((RuntimeXfermode) xfermode).createNativeInstance()); + return xfermode; + } + } + int newMode = (xfermode instanceof PorterDuffXfermode) + ? ((PorterDuffXfermode) xfermode).porterDuffMode : PorterDuffXfermode.DEFAULT; + int curMode = (mXfermode instanceof PorterDuffXfermode) + ? ((PorterDuffXfermode) mXfermode).porterDuffMode : PorterDuffXfermode.DEFAULT; if (newMode != curMode) { nSetXfermode(mNativePaint, newMode); } @@ -3823,6 +3845,8 @@ public class Paint { @CriticalNative private static native void nSetXfermode(long paintPtr, int xfermode); @CriticalNative + private static native void nSetXfermode(long paintPtr, long xfermodePtr); + @CriticalNative private static native long nSetPathEffect(long paintPtr, long effect); @CriticalNative private static native long nSetMaskFilter(long paintPtr, long maskfilter); diff --git a/graphics/java/android/graphics/PorterDuffXfermode.java b/graphics/java/android/graphics/PorterDuffXfermode.java index ff9ff8b0069d..83d0507a5074 100644 --- a/graphics/java/android/graphics/PorterDuffXfermode.java +++ b/graphics/java/android/graphics/PorterDuffXfermode.java @@ -29,6 +29,9 @@ public class PorterDuffXfermode extends Xfermode { * * @param mode The porter-duff mode that is applied */ + static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt; + int porterDuffMode = DEFAULT; + PorterDuffXfermode() {} public PorterDuffXfermode(PorterDuff.Mode mode) { porterDuffMode = mode.nativeInt; } diff --git a/graphics/java/android/graphics/RuntimeColorFilter.java b/graphics/java/android/graphics/RuntimeColorFilter.java index 52724ceaf301..d112f7153fca 100644 --- a/graphics/java/android/graphics/RuntimeColorFilter.java +++ b/graphics/java/android/graphics/RuntimeColorFilter.java @@ -283,6 +283,23 @@ public class RuntimeColorFilter extends ColorFilter { nativeUpdateChild(getNativeInstance(), filterName, colorFilter.getNativeInstance()); } + /** + * Assigns the uniform xfermode to the provided xfermode parameter. If the shader program does + * not have a uniform xfermode with that name then an IllegalArgumentException is thrown. + * + * @param xfermodeName name matching the uniform declared in the AGSL program + * @param xfermode filter passed into the AGSL program for sampling + */ + public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) { + if (xfermodeName == null) { + throw new NullPointerException("The xfermodeName parameter must not be null"); + } + if (xfermode == null) { + throw new NullPointerException("The xfermode parameter must not be null"); + } + nativeUpdateChild(getNativeInstance(), xfermodeName, xfermode.createNativeInstance()); + } + /** @hide */ @Override protected long createNativeInstance() { diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java index 78d257f86613..6316c1fb8b47 100644 --- a/graphics/java/android/graphics/RuntimeShader.java +++ b/graphics/java/android/graphics/RuntimeShader.java @@ -18,10 +18,13 @@ package android.graphics; import android.annotation.ColorInt; import android.annotation.ColorLong; +import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.util.ArrayMap; import android.view.Window; +import com.android.graphics.hwui.flags.Flags; + import libcore.util.NativeAllocationRegistry; /** @@ -525,6 +528,45 @@ public class RuntimeShader extends Shader { discardNativeInstance(); } + /** + * Assigns the uniform color filter to the provided color filter parameter. If the shader + * program does not have a uniform color filter with that name then an IllegalArgumentException + * is thrown. + * + * @param filterName name matching the uniform declared in the AGSL program + * @param colorFilter filter passed into the AGSL program for sampling + */ + @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS) + public void setInputColorFilter(@NonNull String filterName, @NonNull ColorFilter colorFilter) { + if (filterName == null) { + throw new NullPointerException("The filterName parameter must not be null"); + } + if (colorFilter == null) { + throw new NullPointerException("The colorFilter parameter must not be null"); + } + nativeUpdateChild(mNativeInstanceRuntimeShaderBuilder, filterName, + colorFilter.getNativeInstance()); + } + + /** + * Assigns the uniform xfermode to the provided xfermode parameter. If the shader program does + * not have a uniform xfermode with that name then an IllegalArgumentException is thrown. + * + * @param xfermodeName name matching the uniform declared in the AGSL program + * @param xfermode filter passed into the AGSL program for sampling + */ + @FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS) + public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) { + if (xfermodeName == null) { + throw new NullPointerException("The xfermodeName parameter must not be null"); + } + if (xfermode == null) { + throw new NullPointerException("The xfermode parameter must not be null"); + } + nativeUpdateChild(mNativeInstanceRuntimeShaderBuilder, xfermodeName, + xfermode.createNativeInstance()); + } + /** @hide */ @Override @@ -552,5 +594,7 @@ public class RuntimeShader extends Shader { int value4, int count); private static native void nativeUpdateShader( long shaderBuilder, String shaderName, long shader); + private static native void nativeUpdateChild( + long shaderBuilder, String childName, long child); } diff --git a/graphics/java/android/graphics/RuntimeXfermode.java b/graphics/java/android/graphics/RuntimeXfermode.java new file mode 100644 index 000000000000..51d97a4b7487 --- /dev/null +++ b/graphics/java/android/graphics/RuntimeXfermode.java @@ -0,0 +1,329 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics; + +import android.annotation.ColorInt; +import android.annotation.ColorLong; +import android.annotation.FlaggedApi; +import android.annotation.NonNull; + +import com.android.graphics.hwui.flags.Flags; + +import libcore.util.NativeAllocationRegistry; + + +/** + * <p>A {@link RuntimeXfermode} calculates a per-pixel color based on the output of a user + * * defined Android Graphics Shading Language (AGSL) function.</p> + * + * <p>This AGSL function takes in two input colors to be operated on. These colors are in sRGB + * * and the output is also interpreted as sRGB. The AGSL function signature expects a single input + * * of color (packed as a half4 or float4 or vec4).</p> + * + * <pre class="prettyprint"> + * vec4 main(half4 src, half4 dst); + * </pre> + */ +@FlaggedApi(Flags.FLAG_RUNTIME_COLOR_FILTERS_BLENDERS) +public class RuntimeXfermode extends Xfermode { + + private static class NoImagePreloadHolder { + public static final NativeAllocationRegistry sRegistry = + NativeAllocationRegistry.createMalloced( + RuntimeXfermode.class.getClassLoader(), nativeGetFinalizer()); + } + + private long mBuilderNativeInstance; + + /** + * Creates a new RuntimeBlender. + * + * @param agsl The text of AGSL color filter program to run. + */ + public RuntimeXfermode(@NonNull String agsl) { + if (agsl == null) { + throw new NullPointerException("RuntimeShader requires a non-null AGSL string"); + } + mBuilderNativeInstance = nativeCreateBlenderBuilder(agsl); + RuntimeXfermode.NoImagePreloadHolder.sRegistry.registerNativeAllocation( + this, mBuilderNativeInstance); + } + /** + * Sets the uniform color value corresponding to this color filter. If the effect does not have + * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4 + * and corresponding layout(color) annotation then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the color uniform declared in the AGSL program + * @param color the provided sRGB color + */ + public void setColorUniform(@NonNull String uniformName, @ColorInt int color) { + setUniform(uniformName, Color.valueOf(color).getComponents(), true); + } + + /** + * Sets the uniform color value corresponding to this color filter. If the effect does not have + * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4 + * and corresponding layout(color) annotation then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the color uniform declared in the AGSL program + * @param color the provided sRGB color + */ + public void setColorUniform(@NonNull String uniformName, @ColorLong long color) { + Color exSRGB = Color.valueOf(color).convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); + setUniform(uniformName, exSRGB.getComponents(), true); + } + + /** + * Sets the uniform color value corresponding to this color filter. If the effect does not have + * a uniform with that name or if the uniform is declared with a type other than vec3 or vec4 + * and corresponding layout(color) annotation then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the color uniform declared in the AGSL program + * @param color the provided sRGB color + */ + public void setColorUniform(@NonNull String uniformName, @NonNull Color color) { + if (color == null) { + throw new NullPointerException("The color parameter must not be null"); + } + Color exSRGB = color.convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB)); + setUniform(uniformName, exSRGB.getComponents(), true); + } + + /** + * Sets the uniform value corresponding to this color filter. If the effect does not have a + * uniform with that name or if the uniform is declared with a type other than a float or + * float[1] then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the uniform declared in the AGSL program + */ + public void setFloatUniform(@NonNull String uniformName, float value) { + setFloatUniform(uniformName, value, 0.0f, 0.0f, 0.0f, 1); + } + + /** + * Sets the uniform value corresponding to this color filter. If the effect does not have a + * uniform with that name or if the uniform is declared with a type other than a vec2 or + * float[2] then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the uniform declared in the AGSL program + */ + public void setFloatUniform(@NonNull String uniformName, float value1, float value2) { + setFloatUniform(uniformName, value1, value2, 0.0f, 0.0f, 2); + } + + /** + * Sets the uniform value corresponding to this color filter. If the effect does not have a + * uniform with that name or if the uniform is declared with a type other than a vec3 or + * float[3] then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the uniform declared in the AGSL program + */ + public void setFloatUniform(@NonNull String uniformName, float value1, float value2, + float value3) { + setFloatUniform(uniformName, value1, value2, value3, 0.0f, 3); + + } + + /** + * Sets the uniform value corresponding to this color filter. If the effect does not have a + * uniform with that name or if the uniform is declared with a type other than a vec4 or + * float[4] then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the uniform declared in the AGSL program + */ + public void setFloatUniform(@NonNull String uniformName, float value1, float value2, + float value3, float value4) { + setFloatUniform(uniformName, value1, value2, value3, value4, 4); + } + + /** + * Sets the uniform value corresponding to this color filter. If the effect does not have a + * uniform with that name or if the uniform is declared with a type other than a float + * (for N=1), vecN, or float[N] where N is the length of the values param then an + * IllegalArgumentException is thrown. + * + * @param uniformName name matching the uniform declared in the AGSL program + */ + public void setFloatUniform(@NonNull String uniformName, @NonNull float[] values) { + setUniform(uniformName, values, false); + } + + private void setFloatUniform(@NonNull String uniformName, float value1, float value2, + float value3, float value4, int count) { + if (uniformName == null) { + throw new NullPointerException("The uniformName parameter must not be null"); + } + nativeUpdateUniforms(mBuilderNativeInstance, uniformName, value1, value2, value3, value4, + count); + } + + private void setUniform(@NonNull String uniformName, @NonNull float[] values, boolean isColor) { + if (uniformName == null) { + throw new NullPointerException("The uniformName parameter must not be null"); + } + if (values == null) { + throw new NullPointerException("The uniform values parameter must not be null"); + } + nativeUpdateUniforms(mBuilderNativeInstance, uniformName, values, isColor); + } + + /** + * Sets the uniform value corresponding to this color filter. If the effect does not have a + * uniform with that name or if the uniform is declared with a type other than an int or int[1] + * then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the uniform declared in the AGSL program + */ + public void setIntUniform(@NonNull String uniformName, int value) { + setIntUniform(uniformName, value, 0, 0, 0, 1); + } + + /** + * Sets the uniform value corresponding to this color filter. If the effect does not have a + * uniform with that name or if the uniform is declared with a type other than an ivec2 or + * int[2] then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the uniform declared in the AGSL program + */ + public void setIntUniform(@NonNull String uniformName, int value1, int value2) { + setIntUniform(uniformName, value1, value2, 0, 0, 2); + } + + /** + * Sets the uniform value corresponding to this color filter. If the effect does not have a + * uniform with that name or if the uniform is declared with a type other than an ivec3 or + * int[3] then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the uniform declared in the AGSL program + */ + public void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3) { + setIntUniform(uniformName, value1, value2, value3, 0, 3); + } + + /** + * Sets the uniform value corresponding to this color filter. If the effect does not have a + * uniform with that name or if the uniform is declared with a type other than an ivec4 or + * int[4] then an IllegalArgumentException is thrown. + * + * @param uniformName name matching the uniform declared in the AGSL program + */ + public void setIntUniform(@NonNull String uniformName, int value1, int value2, + int value3, int value4) { + setIntUniform(uniformName, value1, value2, value3, value4, 4); + } + + /** + * Sets the uniform value corresponding to this color filter. If the effect does not have a + * uniform with that name or if the uniform is declared with a type other than an int (for N=1), + * ivecN, or int[N] where N is the length of the values param then an IllegalArgumentException + * is thrown. + * + * @param uniformName name matching the uniform declared in the AGSL program + */ + public void setIntUniform(@NonNull String uniformName, @NonNull int[] values) { + if (uniformName == null) { + throw new NullPointerException("The uniformName parameter must not be null"); + } + if (values == null) { + throw new NullPointerException("The uniform values parameter must not be null"); + } + nativeUpdateUniforms(mBuilderNativeInstance, uniformName, values); + } + + private void setIntUniform(@NonNull String uniformName, int value1, int value2, int value3, + int value4, int count) { + if (uniformName == null) { + throw new NullPointerException("The uniformName parameter must not be null"); + } + nativeUpdateUniforms(mBuilderNativeInstance, uniformName, value1, value2, value3, value4, + count); + } + + /** + * Assigns the uniform shader to the provided shader parameter. If the shader program does not + * have a uniform shader with that name then an IllegalArgumentException is thrown. + * + * @param shaderName name matching the uniform declared in the AGSL program + * @param shader shader passed into the AGSL program for sampling + */ + public void setInputShader(@NonNull String shaderName, @NonNull Shader shader) { + if (shaderName == null) { + throw new NullPointerException("The shaderName parameter must not be null"); + } + if (shader == null) { + throw new NullPointerException("The shader parameter must not be null"); + } + nativeUpdateChild(mBuilderNativeInstance, shaderName, shader.getNativeInstance()); + } + + /** + * Assigns the uniform color filter to the provided color filter parameter. If the shader + * program does not have a uniform color filter with that name then an IllegalArgumentException + * is thrown. + * + * @param filterName name matching the uniform declared in the AGSL program + * @param colorFilter filter passed into the AGSL program for sampling + */ + public void setInputColorFilter(@NonNull String filterName, @NonNull ColorFilter colorFilter) { + if (filterName == null) { + throw new NullPointerException("The filterName parameter must not be null"); + } + if (colorFilter == null) { + throw new NullPointerException("The colorFilter parameter must not be null"); + } + nativeUpdateChild(mBuilderNativeInstance, filterName, colorFilter.getNativeInstance()); + } + + /** + * Assigns the uniform xfermode to the provided xfermode parameter. If the shader program does + * not have a uniform xfermode with that name then an IllegalArgumentException is thrown. + * + * @param xfermodeName name matching the uniform declared in the AGSL program + * @param xfermode xfermode function passed into the AGSL program for sampling + */ + public void setInputXfermode(@NonNull String xfermodeName, @NonNull RuntimeXfermode xfermode) { + if (xfermodeName == null) { + throw new NullPointerException("The xfermodeName parameter must not be null"); + } + if (xfermode == null) { + throw new NullPointerException("The xfermode parameter must not be null"); + } + nativeUpdateChild(mBuilderNativeInstance, xfermodeName, xfermode.createNativeInstance()); + } + + /** @hide */ + public long createNativeInstance() { + return nativeCreateNativeInstance(mBuilderNativeInstance); + } + + /** @hide */ + private static native long nativeGetFinalizer(); + private static native long nativeCreateBlenderBuilder(String agsl); + private static native long nativeCreateNativeInstance(long builder); + private static native void nativeUpdateUniforms( + long builder, String uniformName, float[] uniforms, boolean isColor); + private static native void nativeUpdateUniforms( + long builder, String uniformName, float value1, float value2, float value3, + float value4, int count); + private static native void nativeUpdateUniforms( + long builder, String uniformName, int[] uniforms); + private static native void nativeUpdateUniforms( + long builder, String uniformName, int value1, int value2, int value3, + int value4, int count); + private static native void nativeUpdateChild(long builder, String childName, long child); + +} diff --git a/graphics/java/android/graphics/Xfermode.java b/graphics/java/android/graphics/Xfermode.java index 6bb22a12280e..fb689e4cb9c2 100644 --- a/graphics/java/android/graphics/Xfermode.java +++ b/graphics/java/android/graphics/Xfermode.java @@ -21,9 +21,6 @@ package android.graphics; -import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; - /** * Xfermode is the base class for objects that are called to implement custom * "transfer-modes" in the drawing pipeline. The static function Create(Modes) @@ -31,8 +28,4 @@ import android.os.Build; * specified in the Modes enum. When an Xfermode is assigned to a Paint, then * objects drawn with that paint have the xfermode applied. */ -public class Xfermode { - static final int DEFAULT = PorterDuff.Mode.SRC_OVER.nativeInt; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - int porterDuffMode = DEFAULT; -} +public class Xfermode {} diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java index 220fc6f82a71..819cf3492d24 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/BackupHelper.java @@ -94,7 +94,6 @@ class BackupHelper { */ void scheduleBackup() { if (!mSaveEmbeddingState) { - // TODO(b/289875940): enabled internally for broader testing. return; } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java index cb280c530c1b..0f1246cd17e3 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableSplitContainerData.java @@ -44,7 +44,6 @@ class ParcelableSplitContainerData implements Parcelable { @NonNull private final IBinder mSecondaryContainerToken; - // TODO(b/289875940): making this as non-null once the tag can be auto-generated from the rule. @Nullable final String mSplitRuleTag; diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java index a79a89a210ac..bf342d76f4c2 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/ParcelableTaskFragmentContainerData.java @@ -25,6 +25,9 @@ import android.os.Parcelable; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; + /** * This class holds the Parcelable data of a {@link TaskFragmentContainer}. */ @@ -61,6 +64,12 @@ class ParcelableTaskFragmentContainerData implements Parcelable { @NonNull final Rect mLastRequestedBounds; + /** + * Individual associated activity tokens in different containers that should be finished on + * exit. + */ + final List<IBinder> mActivitiesToFinishOnExit = new ArrayList<>(); + ParcelableTaskFragmentContainerData(@NonNull IBinder token, @Nullable String overlayTag, @Nullable IBinder associatedActivityToken) { mToken = token; @@ -74,6 +83,7 @@ class ParcelableTaskFragmentContainerData implements Parcelable { mOverlayTag = in.readString(); mAssociatedActivityToken = in.readStrongBinder(); mLastRequestedBounds = in.readTypedObject(Rect.CREATOR); + in.readBinderList(mActivitiesToFinishOnExit); } public static final Creator<ParcelableTaskFragmentContainerData> CREATOR = new Creator<>() { @@ -99,7 +109,7 @@ class ParcelableTaskFragmentContainerData implements Parcelable { dest.writeString(mOverlayTag); dest.writeStrongBinder(mAssociatedActivityToken); dest.writeTypedObject(mLastRequestedBounds, flags); + dest.writeBinderList(mActivitiesToFinishOnExit); } - } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java index faf73c24073f..5ba30ddd2f18 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitContainer.java @@ -98,10 +98,20 @@ class SplitContainer { mCurrentSplitAttributes = mDefaultSplitAttributes; if (shouldFinishPrimaryWithSecondary(splitRule)) { - mSecondaryContainer.addContainerToFinishOnExit(mPrimaryContainer); + addContainerToFinishOnExitWhenRestore(mSecondaryContainer, mPrimaryContainer); } if (shouldFinishSecondaryWithPrimary(splitRule)) { - mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer); + addContainerToFinishOnExitWhenRestore(mPrimaryContainer, mSecondaryContainer); + } + } + + private void addContainerToFinishOnExitWhenRestore( + @NonNull TaskFragmentContainer containerToAdd, + @NonNull TaskFragmentContainer containerToFinish) { + // If an activity was already added to be finished after the restoration, then that's it. + // Otherwise, add the container to finish on exit. + if (!containerToAdd.hasActivityToFinishOnExit(containerToFinish)) { + containerToAdd.addContainerToFinishOnExit(containerToFinish); } } diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java index dc1d983997c6..b3e003e7ad95 100644 --- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java +++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java @@ -96,12 +96,6 @@ class TaskFragmentContainer { new ArrayList<>(); /** - * Individual associated activity tokens in different containers that should be finished on - * exit. - */ - private final List<IBinder> mActivitiesToFinishOnExit = new ArrayList<>(); - - /** * The launch options that was used to create this container. Must not {@link Bundle#isEmpty()} * for {@link #isOverlay()} container. */ @@ -114,7 +108,6 @@ class TaskFragmentContainer { /** * Windowing mode that was requested last via {@link android.window.WindowContainerTransaction}. */ - // TODO(b/289875940): review this and other field that might need to be moved in the base class. @WindowingMode private int mLastRequestedWindowingMode = WINDOWING_MODE_UNDEFINED; @@ -443,7 +436,7 @@ class TaskFragmentContainer { // Remove the activity now because there can be a delay before the server callback. mInfo.getActivities().remove(activityToken); } - mActivitiesToFinishOnExit.remove(activityToken); + mParcelableData.mActivitiesToFinishOnExit.remove(activityToken); finishSelfWithActivityIfNeeded(wct, activityToken); } @@ -624,7 +617,20 @@ class TaskFragmentContainer { if (mIsFinished) { return; } - mActivitiesToFinishOnExit.add(activityToFinish.getActivityToken()); + mParcelableData.mActivitiesToFinishOnExit.add(activityToFinish.getActivityToken()); + } + + /** + * Returns {@code true} if an Activity from the given {@code container} was added to be + * finished on exit. Otherwise, return {@code false}. + */ + boolean hasActivityToFinishOnExit(@NonNull TaskFragmentContainer container) { + for (IBinder activity : mParcelableData.mActivitiesToFinishOnExit) { + if (container.hasActivity(activity)) { + return true; + } + } + return false; } /** @@ -634,7 +640,7 @@ class TaskFragmentContainer { if (mIsFinished) { return; } - mActivitiesToFinishOnExit.remove(activityToRemove.getActivityToken()); + mParcelableData.mActivitiesToFinishOnExit.remove(activityToRemove.getActivityToken()); } /** Removes all dependencies that should be finished when this container is finished. */ @@ -643,7 +649,7 @@ class TaskFragmentContainer { return; } mContainersToFinishOnExit.clear(); - mActivitiesToFinishOnExit.clear(); + mParcelableData.mActivitiesToFinishOnExit.clear(); } /** @@ -721,7 +727,7 @@ class TaskFragmentContainer { mContainersToFinishOnExit.clear(); // Finish associated activities - for (IBinder activityToken : mActivitiesToFinishOnExit) { + for (IBinder activityToken : mParcelableData.mActivitiesToFinishOnExit) { final Activity activity = mController.getActivity(activityToken); if (activity == null || activity.isFinishing() || controller.shouldRetainAssociatedActivity(this, activity)) { @@ -729,7 +735,7 @@ class TaskFragmentContainer { } wct.finishActivity(activity.getActivityToken()); } - mActivitiesToFinishOnExit.clear(); + mParcelableData.mActivitiesToFinishOnExit.clear(); } @GuardedBy("mController.mLock") @@ -1082,7 +1088,7 @@ class TaskFragmentContainer { + " pendingAppearedActivities=" + mPendingAppearedActivities + (includeContainersToFinishOnExit ? " containersToFinishOnExit=" + containersToFinishOnExitToString() : "") - + " activitiesToFinishOnExit=" + mActivitiesToFinishOnExit + + " activitiesToFinishOnExit=" + mParcelableData.mActivitiesToFinishOnExit + " info=" + mInfo + "}"; } diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml index a18a2510f0f7..bfd9c818a96e 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml @@ -23,7 +23,7 @@ android:clipChildren="false" android:clipToPadding="false" android:paddingBottom="@dimen/desktop_mode_handle_menu_pill_elevation" - android:paddingRight="@dimen/desktop_mode_handle_menu_pill_elevation" + android:paddingEnd="@dimen/desktop_mode_handle_menu_pill_elevation" android:orientation="vertical"> <LinearLayout diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml index 249e9a26e6a6..7078d66d265c 100644 --- a/libs/WindowManager/Shell/res/values/dimen.xml +++ b/libs/WindowManager/Shell/res/values/dimen.xml @@ -661,4 +661,7 @@ <dimen name="desktop_windowing_education_promo_height">352dp</dimen> <!-- The corner radius of the desktop windowing education promo. --> <dimen name="desktop_windowing_education_promo_corner_radius">28dp</dimen> + + <!-- The corner radius of freeform tasks in desktop windowing. --> + <dimen name="desktop_windowing_freeform_rounded_corner_radius">16dp</dimen> </resources> diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java index 03e0ab0591a1..4300e84e8044 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/GroupedTaskInfo.java @@ -168,6 +168,16 @@ public class GroupedTaskInfo implements Parcelable { } /** + * @return The task info for the task in this group with the given {@code taskId}. + */ + @Nullable + public TaskInfo getTaskById(int taskId) { + return mTasks.stream() + .filter(task -> task.taskId == taskId) + .findFirst().orElse(null); + } + + /** * Get all {@link RecentTaskInfo}s grouped together. */ @NonNull @@ -176,6 +186,14 @@ public class GroupedTaskInfo implements Parcelable { } /** + * @return Whether this grouped task contains a task with the given {@code taskId}. + */ + public boolean containsTask(int taskId) { + return mTasks.stream() + .anyMatch((task -> task.taskId == taskId)); + } + + /** * Return {@link SplitBounds} if this is a split screen entry or {@code null} */ @Nullable @@ -249,9 +267,10 @@ public class GroupedTaskInfo implements Parcelable { return null; } return "id=" + taskInfo.taskId - + " baseIntent=" + (taskInfo.baseIntent != null - ? taskInfo.baseIntent.getComponent() - : "null") + + " baseIntent=" + + (taskInfo.baseIntent != null && taskInfo.baseIntent.getComponent() != null + ? taskInfo.baseIntent.getComponent().flattenToString() + : "null") + " winMode=" + WindowConfiguration.windowingModeToString( taskInfo.getWindowingMode()); } diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt index 23e7441ff86b..f14dfdbc7d30 100644 --- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt +++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/ManageWindowsViewContainer.kt @@ -50,6 +50,22 @@ abstract class ManageWindowsViewContainer( fun createMenu(snapshotList: List<Pair<Int, TaskSnapshot>>, onIconClickListener: ((Int) -> Unit), onOutsideClickListener: (() -> Unit)): ManageWindowsView { + val bitmapList = snapshotList.map { (index, snapshot) -> + index to Bitmap.wrapHardwareBuffer(snapshot.hardwareBuffer, snapshot.colorSpace) + } + return createAndShowMenuView( + bitmapList, + onIconClickListener, + onOutsideClickListener + ) + } + + /** Creates the menu view with the given bitmaps, and displays it. */ + fun createAndShowMenuView( + snapshotList: List<Pair<Int, Bitmap?>>, + onIconClickListener: ((Int) -> Unit), + onOutsideClickListener: (() -> Unit) + ): ManageWindowsView { menuView = ManageWindowsView(context, menuBackgroundColor).apply { this.onOutsideClickListener = onOutsideClickListener this.onIconClickListener = onIconClickListener @@ -120,7 +136,7 @@ abstract class ManageWindowsViewContainer( } fun generateIconViews( - snapshotList: List<Pair<Int, TaskSnapshot>> + snapshotList: List<Pair<Int, Bitmap?>> ) { menuWidth = 0 menuHeight = 0 @@ -133,7 +149,7 @@ abstract class ManageWindowsViewContainer( // Add each icon to the menu, adding a new row when needed. for ((iconCount, taskInfoSnapshotPair) in snapshotList.withIndex()) { val taskId = taskInfoSnapshotPair.first - val snapshot = taskInfoSnapshotPair.second + val snapshotBitmap = taskInfoSnapshotPair.second // Once a row is filled, make a new row and increase the menu height. if (iconCount % MENU_MAX_ICONS_PER_ROW == 0) { rowLayout = LinearLayout(context) @@ -141,10 +157,7 @@ abstract class ManageWindowsViewContainer( rootView.addView(rowLayout) menuHeight += (instanceIconHeight + iconMargin).toInt() } - val snapshotBitmap = Bitmap.wrapHardwareBuffer( - snapshot.hardwareBuffer, - snapshot.colorSpace - ) + val croppedBitmap = snapshotBitmap?.let { cropBitmap(it) } val scaledSnapshotBitmap = croppedBitmap?.let { Bitmap.createScaledBitmap( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 39dc26797a81..603a9ec6bedb 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -2087,8 +2087,9 @@ public class BubbleController implements ConfigurationChangeListener, BubbleLogger.Event event = isExpanded ? BubbleLogger.Event.BUBBLE_BAR_EXPANDED : BubbleLogger.Event.BUBBLE_BAR_COLLAPSED; - if (mBubbleData.getSelectedBubble() instanceof Bubble bubble) { - mLogger.log(bubble, event); + BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble(); + if (selectedBubble instanceof Bubble) { + mLogger.log((Bubble) selectedBubble, event); } else { mLogger.log(event); } @@ -2099,8 +2100,9 @@ public class BubbleController implements ConfigurationChangeListener, // Only need to update the layer view if we're currently expanded for selection changes. if (mLayerView != null && mLayerView.isExpanded()) { mLayerView.showExpandedView(selectedBubble); - if (selectedBubble instanceof Bubble bubble) { - mLogger.log(bubble, BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED); + if (selectedBubble instanceof Bubble) { + mLogger.log((Bubble) selectedBubble, + BubbleLogger.Event.BUBBLE_BAR_BUBBLE_SWITCHED); } } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java index f532be6b8277..12d20bf0e517 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java @@ -96,6 +96,14 @@ public class DisplayController { } /** + * Get all the displays from DisplayManager. + */ + public Display[] getDisplays() { + final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class); + return displayManager.getDisplays(); + } + + /** * Gets the DisplayLayout associated with a display. */ public @Nullable DisplayLayout getDisplayLayout(int displayId) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt new file mode 100644 index 000000000000..819b11095a9b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxCommandHandler.kt @@ -0,0 +1,184 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui.letterbox + +import android.content.Context +import android.graphics.Color +import com.android.internal.protolog.ProtoLog +import com.android.window.flags.Flags +import com.android.wm.shell.dagger.WMSingleton +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT +import com.android.wm.shell.sysui.ShellCommandHandler +import com.android.wm.shell.sysui.ShellCommandHandler.ShellCommandActionHandler +import com.android.wm.shell.sysui.ShellInit +import java.io.PrintWriter +import javax.inject.Inject + +/** + * Handles the shell commands for the CompatUI. + * + * <p> Use with [adb shell dumpsys activity service SystemUIService WMShell letterbox + * <command>]. + */ +@WMSingleton +class LetterboxCommandHandler @Inject constructor( + private val context: Context, + shellInit: ShellInit, + shellCommandHandler: ShellCommandHandler, + private val letterboxConfiguration: LetterboxConfiguration +) : ShellCommandActionHandler { + + companion object { + @JvmStatic + private val TAG = "LetterboxCommandHandler" + } + + init { + if (Flags.appCompatRefactoring()) { + ProtoLog.v( + WM_SHELL_APP_COMPAT, + "%s: %s", + TAG, + "Initializing LetterboxCommandHandler" + ) + shellInit.addInitCallback({ + shellCommandHandler.addCommandCallback("letterbox", this, this) + }, this) + } + } + + override fun onShellCommand(args: Array<out String>?, pw: PrintWriter?): Boolean { + if (args == null || pw == null) { + pw!!.println("Missing arguments.") + return false + } + return when (args.size) { + 1 -> onShellDisplayCommand(args[0], pw) + 2 -> onShellUpdateCommand(args[0], args[1], pw) + else -> { + pw.println("Invalid command: " + args[0]) + return false + } + } + } + + override fun printShellCommandHelp(pw: PrintWriter?, prefix: String?) { + pw?.println( + """ + $prefix backgroundColor color" + $prefix Color of letterbox which is to be used when letterbox background + $prefix type is 'solid-color'. See Color#parseColor for allowed color + $prefix formats (#RRGGBB and some colors by name, e.g. magenta or olive). + $prefix backgroundColorResource resource_name" + $prefix Color resource name of letterbox background which is used when + $prefix background type is 'solid-color'. Parameter is a color resource + $prefix name, for example, @android:color/system_accent2_50. + $prefix backgroundColorReset" + $prefix Resets the background color to the default value." + """.trimIndent() + ) + } + + private fun onShellUpdateCommand(command: String, value: String, pw: PrintWriter): Boolean { + when (command) { + "backgroundColor" -> { + return invokeWhenValid( + pw, + value, + ::strToColor, + { color -> + letterboxConfiguration.setLetterboxBackgroundColor(color) + }, + { c -> "$c is not a valid color." } + ) + } + + "backgroundColorResource" -> return invokeWhenValid( + pw, + value, + ::nameToColorId, + { color -> + letterboxConfiguration.setLetterboxBackgroundColorResourceId(color) + }, + { c -> + "$c is not a valid resource. Color in '@android:color/resource_name'" + + " format should be provided as an argument." + } + ) + + "backgroundColorReset" -> { + letterboxConfiguration.resetLetterboxBackgroundColor() + return true + } + + else -> { + pw.println("Invalid command: $value") + return false + } + } + } + + private fun onShellDisplayCommand(command: String, pw: PrintWriter): Boolean { + when (command) { + "backgroundColor" -> { + pw.println( + " Background color: " + Integer.toHexString( + letterboxConfiguration.getLetterboxBackgroundColor() + .toArgb() + ) + ) + return true + } + + else -> { + pw.println("Invalid command: $command") + return false + } + } + } + + private fun <T> invokeWhenValid( + pw: PrintWriter, + input: String, + converter: (String) -> T?, + consumer: (T) -> Unit, + errorMessage: (String) -> String = { value -> " Wrong input value: $value." } + ): Boolean { + converter(input)?.let { + consumer(it) + return true + } + pw.println(errorMessage(input)) + return false + } + + // Converts a String to Color if possible or it returns null otherwise. + private fun strToColor(str: String): Color? = + try { + Color.valueOf(Color.parseColor(str)) + } catch (e: IllegalArgumentException) { + null + } + + // Converts a resource id to Color if possible or it returns null otherwise. + private fun nameToColorId(str: String): Int? = + try { + context.resources.getIdentifier(str, "color", "com.android.internal") + } catch (e: IllegalArgumentException) { + null + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxConfiguration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxConfiguration.kt new file mode 100644 index 000000000000..83a8e3103e3f --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxConfiguration.kt @@ -0,0 +1,82 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui.letterbox + +import android.annotation.ColorRes +import android.content.Context +import android.graphics.Color +import com.android.internal.R +import com.android.wm.shell.dagger.WMSingleton +import javax.inject.Inject + +/** + * Contains configuration properties for the letterbox implementation in Shell. + */ +@WMSingleton +class LetterboxConfiguration @Inject constructor( + private val context: Context +) { + // Color to use for the solid color letterbox background type. + private var letterboxBackgroundColorOverride: Color? = null + + // Color resource id for the solid color letterbox background type. + private var letterboxBackgroundColorResourceIdOverride: Int? = null + + /** + * Sets color of letterbox background which is used when using the solid background mode. + */ + fun setLetterboxBackgroundColor(color: Color) { + letterboxBackgroundColorOverride = color + } + + /** + * Sets color ID of letterbox background which is used when using the solid background mode. + */ + fun setLetterboxBackgroundColorResourceId(@ColorRes colorId: Int) { + letterboxBackgroundColorResourceIdOverride = colorId + } + + /** + * Gets color of letterbox background which is used when the solid color mode is active. + */ + fun getLetterboxBackgroundColor(): Color { + if (letterboxBackgroundColorOverride != null) { + return letterboxBackgroundColorOverride!! + } + val colorId = if (letterboxBackgroundColorResourceIdOverride != null) { + letterboxBackgroundColorResourceIdOverride + } else { + R.color.config_letterboxBackgroundColor + } + // Query color dynamically because material colors extracted from wallpaper are updated + // when wallpaper is changed. + return Color.valueOf(context.getResources().getColor(colorId!!, /* theme */null)) + } + + /** + * Resets color of letterbox background to the default. + */ + fun resetLetterboxBackgroundColor() { + letterboxBackgroundColorOverride = null + letterboxBackgroundColorResourceIdOverride = null + } + + /** + * The background color for the Letterbox. + */ + fun getBackgroundColorRgbArray(): FloatArray = getLetterboxBackgroundColor().components +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt new file mode 100644 index 000000000000..0ac7aff306a0 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxController.kt @@ -0,0 +1,150 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui.letterbox + +import android.graphics.Rect +import android.view.SurfaceControl +import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.dagger.WMSingleton +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT +import javax.inject.Inject + +/** + * Component responsible for handling the lifecycle of the letterbox surfaces. + */ +@WMSingleton +class LetterboxController @Inject constructor( + private val letterboxConfiguration: LetterboxConfiguration +) { + + companion object { + /* + * Letterbox surfaces need to stay below the activity layer which is 0. + */ + // TODO(b/378673153): Consider adding this to [TaskConstants]. + @JvmStatic + private val TASK_CHILD_LAYER_LETTERBOX_BACKGROUND = -1000 + @JvmStatic + private val TAG = "LetterboxController" + } + + private val letterboxMap = mutableMapOf<LetterboxKey, LetterboxItem>() + + /** + * Creates a Letterbox Surface for a given displayId/taskId if it doesn't exist. + */ + fun createLetterboxSurface( + key: LetterboxKey, + startTransaction: SurfaceControl.Transaction, + parentLeash: SurfaceControl + ) { + letterboxMap.runOnItem(key, onMissed = { k, m -> + m[k] = LetterboxItem( + SurfaceControl.Builder() + .setName("ShellLetterboxSurface-$key") + .setHidden(true) + .setColorLayer() + .setParent(parentLeash) + .setCallsite("LetterboxController-createLetterboxSurface") + .build().apply { + startTransaction.setLayer( + this, + TASK_CHILD_LAYER_LETTERBOX_BACKGROUND + ).setColorSpaceAgnostic(this, true) + .setColor(this, letterboxConfiguration.getBackgroundColorRgbArray()) + } + ) + }) + } + + /** + * Invoked to destroy the surfaces for a letterbox session for given displayId/taskId. + */ + fun destroyLetterboxSurface( + key: LetterboxKey, + startTransaction: SurfaceControl.Transaction + ) { + letterboxMap.runOnItem(key, onFound = { item -> + item.fullWindowSurface?.run { + startTransaction.remove(this) + } + }) + letterboxMap.remove(key) + } + + /** + * Invoked to show/hide the letterbox surfaces for given displayId/taskId. + */ + fun updateLetterboxSurfaceVisibility( + key: LetterboxKey, + startTransaction: SurfaceControl.Transaction, + visible: Boolean = true + ) { + letterboxMap.runOnItem(key, onFound = { item -> + item.fullWindowSurface?.run { + startTransaction.setVisibility(this, visible) + } + }) + } + + /** + * Updates the bounds for the letterbox surfaces for given displayId/taskId. + */ + fun updateLetterboxSurfaceBounds( + key: LetterboxKey, + startTransaction: SurfaceControl.Transaction, + bounds: Rect + ) { + letterboxMap.runOnItem(key, onFound = { item -> + item.fullWindowSurface?.run { + startTransaction.moveAndCrop(this, bounds) + } + }) + } + + /* + * Executes [onFound] on the [LetterboxItem] if present or [onMissed] if not present. + */ + private fun MutableMap<LetterboxKey, LetterboxItem>.runOnItem( + key: LetterboxKey, + onFound: (LetterboxItem) -> Unit = { _ -> }, + onMissed: ( + LetterboxKey, + MutableMap<LetterboxKey, LetterboxItem> + ) -> Unit = { _, _ -> } + ) { + this[key]?.let { + return onFound(it) + } + return onMissed(key, this) + } + + fun dump() { + ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}") + } + + private fun SurfaceControl.Transaction.moveAndCrop( + surface: SurfaceControl, + rect: Rect + ): SurfaceControl.Transaction = + setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) + .setWindowCrop( + surface, + rect.width(), + rect.height() + ) +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt new file mode 100644 index 000000000000..98fd2472f1e4 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxData.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui.letterbox + +import android.view.SurfaceControl + +// The key to use for identify the letterbox sessions. +data class LetterboxKey(val displayId: Int, val taskId: Int) + +// Encapsulate the objects for the specific letterbox session. +data class LetterboxItem(val fullWindowSurface: SurfaceControl?)
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt new file mode 100644 index 000000000000..67429bdd112b --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserver.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui.letterbox + +import android.graphics.Rect +import android.os.IBinder +import android.view.SurfaceControl +import android.window.TransitionInfo +import com.android.internal.protolog.ProtoLog +import com.android.window.flags.Flags.appCompatRefactoring +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT +import com.android.wm.shell.shared.TransitionUtil.isClosingType +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.transition.Transitions + +/** + * The [TransitionObserver] to handle Letterboxing events in Shell. + */ +class LetterboxTransitionObserver( + shellInit: ShellInit, + private val transitions: Transitions, + private val letterboxController: LetterboxController +) : Transitions.TransitionObserver { + + companion object { + @JvmStatic + private val TAG = "LetterboxTransitionObserver" + } + + init { + if (appCompatRefactoring()) { + ProtoLog.v( + WM_SHELL_APP_COMPAT, + "%s: %s", + TAG, + "Initializing LetterboxTransitionObserver" + ) + shellInit.addInitCallback({ + transitions.registerObserver(this) + }, this) + } + } + + override fun onTransitionReady( + transition: IBinder, + info: TransitionInfo, + startTransaction: SurfaceControl.Transaction, + finishTransaction: SurfaceControl.Transaction + ) { + // We recognise the operation to execute and delegate to the LetterboxController + // the related operation. + // TODO(b/377875151): Identify Desktop Windowing Transactions. + // TODO(b/377857898): Handling multiple surfaces + // TODO(b/371500295): Handle input events detection. + for (change in info.changes) { + change.taskInfo?.let { ti -> + val key = LetterboxKey(ti.displayId, ti.taskId) + if (isClosingType(change.mode)) { + letterboxController.destroyLetterboxSurface( + key, + startTransaction + ) + } else { + val isTopActivityLetterboxed = ti.appCompatTaskInfo.isTopActivityLetterboxed + if (isTopActivityLetterboxed) { + letterboxController.createLetterboxSurface( + key, + startTransaction, + change.leash + ) + letterboxController.updateLetterboxSurfaceBounds( + key, + startTransaction, + Rect( + change.endRelOffset.x, + change.endRelOffset.y, + change.endAbsBounds.width(), + change.endAbsBounds.height() + ) + ) + } + letterboxController.updateLetterboxSurfaceVisibility( + key, + startTransaction, + isTopActivityLetterboxed + ) + } + letterboxController.dump() + } + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 77e041ee7cdb..02df38e03d7c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -795,13 +795,14 @@ public abstract class WMShellBaseModule { static KeyguardTransitionHandler provideKeyguardTransitionHandler( ShellInit shellInit, ShellController shellController, + DisplayController displayController, Transitions transitions, TaskStackListenerImpl taskStackListener, @ShellMainThread Handler mainHandler, @ShellMainThread ShellExecutor mainExecutor) { return new KeyguardTransitionHandler( - shellInit, shellController, transitions, taskStackListener, mainHandler, - mainExecutor); + shellInit, shellController, displayController, transitions, taskStackListener, + mainHandler, mainExecutor); } @WMSingleton @@ -1024,10 +1025,13 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static TaskStackTransitionObserver provideTaskStackTransitionObserver( - Lazy<Transitions> transitions, - ShellInit shellInit + ShellInit shellInit, + Lazy<ShellTaskOrganizer> shellTaskOrganizer, + ShellCommandHandler shellCommandHandler, + Lazy<Transitions> transitions ) { - return new TaskStackTransitionObserver(transitions, shellInit); + return new TaskStackTransitionObserver(shellInit, shellTaskOrganizer, shellCommandHandler, + transitions); } // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 601cf70b93ed..96f80245c76c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -20,6 +20,10 @@ import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_ENTER_TRA import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT; import static android.window.DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS; +import static com.android.hardware.input.Flags.manageKeyGestures; +import static com.android.hardware.input.Flags.useKeyGestureEventHandler; + +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.KeyguardManager; import android.content.Context; @@ -62,6 +66,9 @@ import com.android.wm.shell.common.MultiInstanceHelper; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.TaskStackListenerImpl; +import com.android.wm.shell.compatui.letterbox.LetterboxCommandHandler; +import com.android.wm.shell.compatui.letterbox.LetterboxController; +import com.android.wm.shell.compatui.letterbox.LetterboxTransitionObserver; import com.android.wm.shell.dagger.back.ShellBackAnimationModule; import com.android.wm.shell.dagger.pip.PipModule; import com.android.wm.shell.desktopmode.CloseDesktopTaskTransitionHandler; @@ -73,6 +80,7 @@ import com.android.wm.shell.desktopmode.DesktopImmersiveController; import com.android.wm.shell.desktopmode.DesktopMixedTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeDragAndDropTransitionHandler; import com.android.wm.shell.desktopmode.DesktopModeEventLogger; +import com.android.wm.shell.desktopmode.DesktopModeKeyGestureHandler; import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver; import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.desktopmode.DesktopTaskChangeListener; @@ -755,8 +763,6 @@ public abstract class WMShellModule { dragToDesktopTransitionHandler, desktopImmersiveController.get(), desktopRepository, - desktopModeLoggerTransitionObserver, - launchAdjacentController, recentsTransitionHandler, multiInstanceHelper, mainExecutor, @@ -764,8 +770,6 @@ public abstract class WMShellModule { recentTasksController.orElse(null), interactionJankMonitor, mainHandler, - inputManager, - focusTransitionObserver, desktopModeEventLogger, desktopTilingDecorViewModel); } @@ -880,6 +884,72 @@ public abstract class WMShellModule { @WMSingleton @Provides + static Optional<DesktopModeKeyGestureHandler> provideDesktopModeKeyGestureHandler( + Context context, + Optional<DesktopModeWindowDecorViewModel> desktopModeWindowDecorViewModel, + Optional<DesktopTasksController> desktopTasksController, + InputManager inputManager, + ShellTaskOrganizer shellTaskOrganizer, + FocusTransitionObserver focusTransitionObserver) { + if (DesktopModeStatus.canEnterDesktopMode(context) && useKeyGestureEventHandler() + && manageKeyGestures() + && (Flags.enableMoveToNextDisplayShortcut() + || Flags.enableTaskResizingKeyboardShortcuts())) { + return Optional.of(new DesktopModeKeyGestureHandler(context, + desktopModeWindowDecorViewModel, desktopTasksController, + inputManager, shellTaskOrganizer, focusTransitionObserver)); + } + return Optional.empty(); + } + + @WMSingleton + @Provides + static Optional<DesktopModeWindowDecorViewModel> provideDesktopModeWindowDecorViewModel( + Context context, + @ShellMainThread ShellExecutor shellExecutor, + @ShellMainThread Handler mainHandler, + Choreographer mainChoreographer, + @ShellBackgroundThread ShellExecutor bgExecutor, + ShellInit shellInit, + ShellCommandHandler shellCommandHandler, + IWindowManager windowManager, + ShellTaskOrganizer taskOrganizer, + @DynamicOverride DesktopRepository desktopRepository, + DisplayController displayController, + ShellController shellController, + DisplayInsetsController displayInsetsController, + SyncTransactionQueue syncQueue, + Transitions transitions, + Optional<DesktopTasksController> desktopTasksController, + RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, + InteractionJankMonitor interactionJankMonitor, + AppToWebGenericLinksParser genericLinksParser, + AssistContentRequester assistContentRequester, + MultiInstanceHelper multiInstanceHelper, + Optional<DesktopTasksLimiter> desktopTasksLimiter, + AppHandleEducationController appHandleEducationController, + AppToWebEducationController appToWebEducationController, + WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository, + Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler, + FocusTransitionObserver focusTransitionObserver, + DesktopModeEventLogger desktopModeEventLogger + ) { + if (!DesktopModeStatus.canEnterDesktopMode(context)) { + return Optional.empty(); + } + return Optional.of(new DesktopModeWindowDecorViewModel(context, shellExecutor, mainHandler, + mainChoreographer, bgExecutor, shellInit, shellCommandHandler, windowManager, + taskOrganizer, desktopRepository, displayController, shellController, + displayInsetsController, syncQueue, transitions, desktopTasksController, + rootTaskDisplayAreaOrganizer, interactionJankMonitor, genericLinksParser, + assistContentRequester, multiInstanceHelper, desktopTasksLimiter, + appHandleEducationController, appToWebEducationController, + windowDecorCaptionHandleRepository, activityOrientationChangeHandler, + focusTransitionObserver, desktopModeEventLogger)); + } + + @WMSingleton + @Provides static EnterDesktopTaskTransitionHandler provideEnterDesktopModeTaskTransitionHandler( Transitions transitions, Optional<DesktopTasksLimiter> desktopTasksLimiter, @@ -1229,8 +1299,25 @@ public abstract class WMShellModule { @Provides static Object provideIndependentShellComponentsToCreate( DragAndDropController dragAndDropController, + @NonNull LetterboxTransitionObserver letterboxTransitionObserver, + @NonNull LetterboxCommandHandler letterboxCommandHandler, Optional<DesktopTasksTransitionObserver> desktopTasksTransitionObserverOptional, - Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler) { + Optional<DesktopDisplayEventHandler> desktopDisplayEventHandler, + Optional<DesktopModeKeyGestureHandler> desktopModeKeyGestureHandler) { return new Object(); } + + // + // App Compat + // + + @WMSingleton + @Provides + static LetterboxTransitionObserver provideLetterboxTransitionObserver( + @NonNull ShellInit shellInit, + @NonNull Transitions transitions, + @NonNull LetterboxController letterboxController + ) { + return new LetterboxTransitionObserver(shellInit, transitions, letterboxController); + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt index 2001f9743094..82c2ebc7ec77 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandler.kt @@ -23,6 +23,7 @@ import android.os.Handler import android.os.IBinder import android.view.SurfaceControl import android.view.WindowManager +import android.view.WindowManager.TRANSIT_OPEN import android.window.DesktopModeFlags import android.window.TransitionInfo import android.window.TransitionInfo.Change @@ -95,7 +96,7 @@ class DesktopMixedTransitionHandler( fun startLaunchTransition( @WindowManager.TransitionType transitionType: Int, wct: WindowContainerTransaction, - taskId: Int, + taskId: Int?, minimizingTaskId: Int? = null, exitingImmersiveTask: Int? = null, ): IBinder { @@ -216,12 +217,12 @@ class DesktopMixedTransitionHandler( ): Boolean { // Check if there's also an immersive change during this launch. val immersiveExitChange = pending.exitingImmersiveTask?.let { exitingTask -> - findDesktopTaskChange(info, exitingTask) + findTaskChange(info, exitingTask) } val minimizeChange = pending.minimizingTask?.let { minimizingTask -> - findDesktopTaskChange(info, minimizingTask) + findTaskChange(info, minimizingTask) } - val launchChange = findDesktopTaskChange(info, pending.launchingTask) + val launchChange = findDesktopTaskLaunchChange(info, pending.launchingTask) if (launchChange == null) { check(minimizeChange == null) check(immersiveExitChange == null) @@ -291,7 +292,7 @@ class DesktopMixedTransitionHandler( ): Boolean { if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue) return false - val minimizeChange = findDesktopTaskChange(info, pending.minimizingTask) + val minimizeChange = findTaskChange(info, pending.minimizingTask) if (minimizeChange == null) { logW("Should have minimizing desktop task") return false @@ -417,8 +418,24 @@ class DesktopMixedTransitionHandler( } } - private fun findDesktopTaskChange(info: TransitionInfo, taskId: Int): TransitionInfo.Change? { - return info.changes.firstOrNull { change -> change.taskInfo?.taskId == taskId } + private fun findTaskChange(info: TransitionInfo, taskId: Int): TransitionInfo.Change? = + info.changes.firstOrNull { change -> change.taskInfo?.taskId == taskId } + + private fun findDesktopTaskLaunchChange( + info: TransitionInfo, + launchTaskId: Int? + ): TransitionInfo.Change? { + return if (launchTaskId != null) { + // Launching a known task (probably from background or moving to front), so + // specifically look for it. + findTaskChange(info, launchTaskId) + } else { + // Launching a new task, so the first opening freeform task. + info.changes.firstOrNull { change -> + change.mode == TRANSIT_OPEN + && change.taskInfo != null && change.taskInfo!!.isFreeform + } + } } private fun WindowContainerTransaction?.merge( @@ -441,7 +458,7 @@ class DesktopMixedTransitionHandler( /** A task is opening or moving to front. */ data class Launch( override val transition: IBinder, - val launchingTask: Int, + val launchingTask: Int?, val minimizingTask: Int?, val exitingImmersiveTask: Int?, ) : PendingMixedTransition() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt new file mode 100644 index 000000000000..ac07eaa695c1 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandler.kt @@ -0,0 +1,144 @@ +/* + * 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.desktopmode + +import android.hardware.input.KeyGestureEvent + +import android.hardware.input.InputManager +import android.hardware.input.InputManager.KeyGestureEventHandler +import android.os.IBinder +import com.android.window.flags.Flags.enableMoveToNextDisplayShortcut +import com.android.wm.shell.ShellTaskOrganizer +import android.app.ActivityManager.RunningTaskInfo +import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel +import com.android.internal.protolog.ProtoLog +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.content.Context +import com.android.hardware.input.Flags.manageKeyGestures +import com.android.window.flags.Flags.enableTaskResizingKeyboardShortcuts +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger +import com.android.wm.shell.transition.FocusTransitionObserver +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE +import java.util.Optional + +/** + * Handles key gesture events (keyboard shortcuts) in Desktop Mode. + */ +class DesktopModeKeyGestureHandler( + private val context: Context, + private val desktopModeWindowDecorViewModel: Optional<DesktopModeWindowDecorViewModel>, + private val desktopTasksController: Optional<DesktopTasksController>, + inputManager: InputManager, + private val shellTaskOrganizer: ShellTaskOrganizer, + private val focusTransitionObserver: FocusTransitionObserver, + ) : KeyGestureEventHandler { + + init { + inputManager.registerKeyGestureEventHandler(this) + } + + override fun handleKeyGestureEvent(event: KeyGestureEvent, focusedToken: IBinder?): Boolean { + if (!isKeyGestureSupported(event.keyGestureType) || !desktopTasksController.isPresent + || !desktopModeWindowDecorViewModel.isPresent) { + return false + } + when (event.keyGestureType) { + KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY -> { + logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled") + getGloballyFocusedFreeformTask()?.let { + desktopTasksController.get().moveToNextDisplay( + it.taskId + ) + } + return true + } + // TODO(b/375356876): Modify function to pass in keyboard shortcut as the input + // method for logging task resize + KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW -> { + logV("Key gesture SNAP_LEFT_FREEFORM_WINDOW is handled") + getGloballyFocusedFreeformTask()?.let { + desktopModeWindowDecorViewModel.get().onSnapResize( + it.taskId, + true, + null + ) + } + return true + } + KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW -> { + logV("Key gesture SNAP_RIGHT_FREEFORM_WINDOW is handled") + getGloballyFocusedFreeformTask()?.let { + desktopModeWindowDecorViewModel.get().onSnapResize( + it.taskId, + false, + null + ) + } + return true + } + KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW -> { + logV("Key gesture TOGGLE_MAXIMIZE_FREEFORM_WINDOW is handled") + getGloballyFocusedFreeformTask()?.let { + desktopTasksController.get().toggleDesktopTaskSize( + it, + ResizeTrigger.MAXIMIZE_MENU, + null, + ) + } + return true + } + KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW -> { + logV("Key gesture MINIMIZE_FREEFORM_WINDOW is handled") + getGloballyFocusedFreeformTask()?.let { + desktopTasksController.get().minimizeTask( + it, + ) + } + return true + } + else -> return false + } + } + + override fun isKeyGestureSupported(gestureType: Int): Boolean = when (gestureType) { + KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY + -> enableMoveToNextDisplayShortcut() + KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW, + KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW, + KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW, + KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW + -> enableTaskResizingKeyboardShortcuts() && manageKeyGestures() + else -> false + } + + // TODO: b/364154795 - wait for the completion of moveToNextDisplay transition, otherwise it + // will pick a wrong task when a user quickly perform other actions with keyboard shortcuts + // after moveToNextDisplay, and move this to FocusTransitionObserver class. + private fun getGloballyFocusedFreeformTask(): RunningTaskInfo? = + shellTaskOrganizer.getRunningTasks().find { taskInfo -> + taskInfo.windowingMode == WINDOWING_MODE_FREEFORM && + focusTransitionObserver.hasGlobalFocus(taskInfo) + } + + private fun logV(msg: String, vararg arguments: Any?) { + ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments) + } + + companion object { + private const val TAG = "DesktopModeKeyGestureHandler" + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt index 08ca55f93e3f..7fcb7678f6af 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt @@ -411,6 +411,12 @@ class DesktopRepository ( desktopTaskDataByDisplayId[displayId]?.freeformTasksInZOrder?.toDumpString()) // Remove task from unminimized task if it is minimized. unminimizeTask(displayId, taskId) + // Mark task as not in immersive if it was immersive. + setTaskInFullImmersiveState( + displayId = displayId, + taskId = taskId, + immersive = false + ) removeActiveTask(taskId) removeVisibleTask(taskId) if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) { @@ -487,6 +493,9 @@ class DesktopRepository ( mainCoroutineScope.launch { try { persistentRepository.addOrUpdateDesktop( + // Use display id as desktop id for now since only once desktop per display + // is supported. + desktopId = displayId, visibleTasks = desktopTaskDataByDisplayIdCopy.visibleTasks, minimizedTasks = desktopTaskDataByDisplayIdCopy.minimizedTasks, freeformTasksInZOrder = desktopTaskDataByDisplayIdCopy.freeformTasksInZOrder 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 6928c255edde..8bad87480985 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 @@ -35,9 +35,6 @@ import android.graphics.Point import android.graphics.PointF import android.graphics.Rect import android.graphics.Region -import android.hardware.input.InputManager -import android.hardware.input.InputManager.KeyGestureEventHandler -import android.hardware.input.KeyGestureEvent import android.os.Binder import android.os.Handler import android.os.IBinder @@ -46,7 +43,6 @@ import android.os.UserHandle import android.util.Size import android.view.Display.DEFAULT_DISPLAY import android.view.DragEvent -import android.view.KeyEvent import android.view.MotionEvent import android.view.SurfaceControl import android.view.SurfaceControl.Transaction @@ -66,7 +62,6 @@ import android.window.TransitionInfo.Change import android.window.TransitionRequestInfo import android.window.WindowContainerTransaction import androidx.annotation.BinderThread -import com.android.hardware.input.Flags.useKeyGestureEventHandler import com.android.internal.annotations.VisibleForTesting import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE @@ -75,13 +70,12 @@ import com.android.internal.jank.InteractionJankMonitor import com.android.internal.policy.ScreenDecorationsUtils import com.android.internal.protolog.ProtoLog import com.android.window.flags.Flags -import com.android.window.flags.Flags.enableMoveToNextDisplayShortcut +import com.android.wm.shell.R import com.android.wm.shell.RootTaskDisplayAreaOrganizer import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout import com.android.wm.shell.common.ExternalInterfaceBinder -import com.android.wm.shell.common.LaunchAdjacentController import com.android.wm.shell.common.MultiInstanceHelper import com.android.wm.shell.common.MultiInstanceHelper.Companion.getComponent import com.android.wm.shell.common.RemoteCallable @@ -89,7 +83,6 @@ import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.SingleInstanceRemoteListener import com.android.wm.shell.common.SyncTransactionQueue import com.android.wm.shell.compatui.isTopActivityExemptFromDesktopWindowing -import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.DragStartState import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType import com.android.wm.shell.desktopmode.DesktopRepository.VisibleTasksListener @@ -117,7 +110,6 @@ import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.sysui.UserChangeListener -import com.android.wm.shell.transition.FocusTransitionObserver import com.android.wm.shell.transition.OneShotRemoteHandler import com.android.wm.shell.transition.Transitions import com.android.wm.shell.transition.Transitions.TransitionFinishCallback @@ -157,8 +149,6 @@ class DesktopTasksController( private val dragToDesktopTransitionHandler: DragToDesktopTransitionHandler, private val desktopImmersiveController: DesktopImmersiveController, private val taskRepository: DesktopRepository, - private val desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver, - private val launchAdjacentController: LaunchAdjacentController, private val recentsTransitionHandler: RecentsTransitionHandler, private val multiInstanceHelper: MultiInstanceHelper, @ShellMainThread private val mainExecutor: ShellExecutor, @@ -166,16 +156,13 @@ class DesktopTasksController( private val recentTasksController: RecentTasksController?, private val interactionJankMonitor: InteractionJankMonitor, @ShellMainThread private val handler: Handler, - private val inputManager: InputManager, - private val focusTransitionObserver: FocusTransitionObserver, private val desktopModeEventLogger: DesktopModeEventLogger, private val desktopTilingDecorViewModel: DesktopTilingDecorViewModel, ) : RemoteCallable<DesktopTasksController>, Transitions.TransitionHandler, DragAndDropController.DragAndDropListener, - UserChangeListener, - KeyGestureEventHandler { + UserChangeListener { private val desktopMode: DesktopModeImpl private var visualIndicator: DesktopModeVisualIndicator? = null @@ -249,9 +236,6 @@ class DesktopTasksController( } ) dragAndDropController.addListener(this) - if (useKeyGestureEventHandler() && enableMoveToNextDisplayShortcut()) { - inputManager.registerKeyGestureEventHandler(this) - } } @VisibleForTesting @@ -618,25 +602,18 @@ class DesktopTasksController( private fun moveBackgroundTaskToFront(taskId: Int, remoteTransition: RemoteTransition?) { logV("moveBackgroundTaskToFront taskId=%s", taskId) val wct = WindowContainerTransaction() - // TODO: b/342378842 - Instead of using default display, support multiple displays - val exitResult = desktopImmersiveController.exitImmersiveIfApplicable( - wct = wct, - displayId = DEFAULT_DISPLAY, - excludeTaskId = taskId, - ) wct.startTask( taskId, ActivityOptions.makeBasic().apply { launchWindowingMode = WINDOWING_MODE_FREEFORM }.toBundle(), ) - val transition = startLaunchTransition( + startLaunchTransition( TRANSIT_OPEN, wct, taskId, remoteTransition = remoteTransition ) - exitResult.asExit()?.runOnTransitionStart?.invoke(transition) } /** @@ -655,47 +632,53 @@ class DesktopTasksController( } val wct = WindowContainerTransaction() wct.reorder(taskInfo.token, true /* onTop */, true /* includingParents */) - val result = desktopImmersiveController.exitImmersiveIfApplicable( - wct = wct, - displayId = taskInfo.displayId, - excludeTaskId = taskInfo.taskId, - ) - val exitResult = if (result is ExitResult.Exit) { result } else { null } - val transition = startLaunchTransition( + startLaunchTransition( transitionType = TRANSIT_TO_FRONT, wct = wct, - taskId = taskInfo.taskId, - exitingImmersiveTask = exitResult?.exitingTask, + launchingTaskId = taskInfo.taskId, remoteTransition = remoteTransition, displayId = taskInfo.displayId, ) - exitResult?.runOnTransitionStart?.invoke(transition) } private fun startLaunchTransition( transitionType: Int, wct: WindowContainerTransaction, - taskId: Int, - exitingImmersiveTask: Int? = null, + launchingTaskId: Int?, remoteTransition: RemoteTransition? = null, displayId: Int = DEFAULT_DISPLAY, ): IBinder { - val taskIdToMinimize = addAndGetMinimizeChanges(displayId, wct, taskId) + val taskIdToMinimize = if (launchingTaskId != null) { + addAndGetMinimizeChanges(displayId, wct, newTaskId = launchingTaskId) + } else { + logW("Starting desktop task launch without checking the task-limit") + // TODO(b/378920066): This currently does not respect the desktop window limit. + // It's possible that |launchingTaskId| is null when launching using an intent, and + // the task-limit should be respected then too. + null + } + val exitImmersiveResult = desktopImmersiveController.exitImmersiveIfApplicable( + wct = wct, + displayId = displayId, + excludeTaskId = launchingTaskId, + ) if (remoteTransition == null) { val t = desktopMixedTransitionHandler.startLaunchTransition( transitionType = transitionType, wct = wct, - taskId = taskId, + taskId = launchingTaskId, minimizingTaskId = taskIdToMinimize, - exitingImmersiveTask = exitingImmersiveTask, + exitingImmersiveTask = exitImmersiveResult.asExit()?.exitingTask, ) taskIdToMinimize?.let { addPendingMinimizeTransition(t, it) } + exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t) return t } if (taskIdToMinimize == null) { val remoteTransitionHandler = OneShotRemoteHandler(mainExecutor, remoteTransition) val t = transitions.startTransition(transitionType, wct, remoteTransitionHandler) remoteTransitionHandler.setTransition(t) + exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t) return t } val remoteTransitionHandler = @@ -704,6 +687,7 @@ class DesktopTasksController( val t = transitions.startTransition(transitionType, wct, remoteTransitionHandler) remoteTransitionHandler.setTransition(t) taskIdToMinimize.let { addPendingMinimizeTransition(t, it) } + exitImmersiveResult.asExit()?.runOnTransitionStart?.invoke(t) return t } @@ -794,6 +778,10 @@ class DesktopTasksController( resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, ) { + desktopModeEventLogger.logTaskResizingStarted( + resizeTrigger, motionEvent, taskInfo, displayController + ) + val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return val stableBounds = Rect().apply { displayLayout.getStableBounds(this) } @@ -872,9 +860,6 @@ class DesktopTasksController( return } - desktopModeEventLogger.logTaskResizingStarted( - ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent, taskInfo, displayController - ) toggleDesktopTaskSize(taskInfo, ResizeTrigger.DRAG_TO_TOP_RESIZE_TRIGGER, motionEvent) } @@ -962,13 +947,17 @@ class DesktopTasksController( */ fun snapToHalfScreen( taskInfo: RunningTaskInfo, - taskSurface: SurfaceControl, + taskSurface: SurfaceControl?, currentDragBounds: Rect, position: SnapPosition, resizeTrigger: ResizeTrigger, motionEvent: MotionEvent?, desktopWindowDecoration: DesktopModeWindowDecoration, ) { + desktopModeEventLogger.logTaskResizingStarted( + resizeTrigger, motionEvent, taskInfo, displayController + ) + if (DesktopModeFlags.ENABLE_TILE_RESIZING.isTrue()) { val isTiled = desktopTilingDecorViewModel.snapToHalfScreen( taskInfo, @@ -994,7 +983,7 @@ class DesktopTasksController( // Handle the case where we attempt to snap resize when already snap resized: the task // position won't need to change but we want to animate the surface going back to the // snapped position from the "dragged-to-the-edge" position. - if (destinationBounds != currentDragBounds) { + if (destinationBounds != currentDragBounds && taskSurface != null) { returnToDragStartAnimator.start( taskInfo.taskId, taskSurface, @@ -1011,8 +1000,40 @@ class DesktopTasksController( toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentDragBounds) } + /** + * Handles snap resizing a [taskInfo] to [position] instantaneously, for example when the + * [resizeTrigger] is the snap resize menu using any [motionEvent] or a keyboard shortcut. + */ + fun handleInstantSnapResizingTask( + taskInfo: RunningTaskInfo, + position: SnapPosition, + resizeTrigger: ResizeTrigger, + motionEvent: MotionEvent? = null, + desktopModeWindowDecoration: DesktopModeWindowDecoration, + ) { + if (!isSnapResizingAllowed(taskInfo)) { + Toast.makeText( + getContext(), + R.string.desktop_mode_non_resizable_snap_text, + Toast.LENGTH_SHORT + ).show() + return + } + + snapToHalfScreen( + taskInfo, + null, + taskInfo.configuration.windowConfiguration.bounds, + position, + resizeTrigger, + motionEvent, + desktopModeWindowDecoration + ) + } + + @VisibleForTesting - fun handleSnapResizingTask( + fun handleSnapResizingTaskOnDrag( taskInfo: RunningTaskInfo, position: SnapPosition, taskSurface: SurfaceControl, @@ -1022,7 +1043,7 @@ class DesktopTasksController( desktopModeWindowDecoration: DesktopModeWindowDecoration, ) { releaseVisualIndicator() - if (!taskInfo.isResizeable && DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) { + if (!isSnapResizingAllowed(taskInfo)) { interactionJankMonitor.begin( taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_non_resizable" ) @@ -1047,9 +1068,6 @@ class DesktopTasksController( } else { ResizeTrigger.DRAG_RIGHT } - desktopModeEventLogger.logTaskResizingStarted( - resizeTrigger, motionEvent, taskInfo, displayController - ) interactionJankMonitor.begin( taskSurface, context, handler, CUJ_DESKTOP_MODE_SNAP_RESIZE, "drag_resizable" ) @@ -1065,6 +1083,9 @@ class DesktopTasksController( } } + private fun isSnapResizingAllowed(taskInfo: RunningTaskInfo) = + taskInfo.isResizeable || !DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue() + private fun getSnapBounds(taskInfo: RunningTaskInfo, position: SnapPosition): Rect { val displayLayout = displayController.getDisplayLayout(taskInfo.displayId) ?: return Rect() @@ -1472,10 +1493,14 @@ class DesktopTasksController( ) } WINDOWING_MODE_FREEFORM -> { - // TODO(b/336289597): This currently does not respect the desktop window limit. val wct = WindowContainerTransaction() wct.sendPendingIntent(launchIntent, fillIn, options.toBundle()) - transitions.startTransition(TRANSIT_OPEN, wct, null) + startLaunchTransition( + transitionType = TRANSIT_OPEN, + wct = wct, + launchingTaskId = null, + displayId = callingTaskInfo.displayId + ) } } } @@ -1832,26 +1857,12 @@ class DesktopTasksController( getFocusedFreeformTask(displayId)?.let { requestSplit(it, leftOrTop) } } - /** Move the focused desktop task in given `displayId` to next display. */ - fun moveFocusedTaskToNextDisplay(displayId: Int) { - getFocusedFreeformTask(displayId)?.let { moveToNextDisplay(it.taskId) } - } - private fun getFocusedFreeformTask(displayId: Int): RunningTaskInfo? { return shellTaskOrganizer.getRunningTasks(displayId).find { taskInfo -> taskInfo.isFocused && taskInfo.windowingMode == WINDOWING_MODE_FREEFORM } } - // TODO(b/364154795): wait for the completion of moveToNextDisplay transition, otherwise it will - // pick a wrong task when a user quickly perform other actions with keyboard shortcuts after - // moveToNextDisplay. - private fun getGloballyFocusedFreeformTask(): RunningTaskInfo? = - shellTaskOrganizer.getRunningTasks().find { taskInfo -> - taskInfo.windowingMode == WINDOWING_MODE_FREEFORM && - focusTransitionObserver.hasGlobalFocus(taskInfo) - } - /** * Requests a task be transitioned from desktop to split select. Applies needed windowing * changes if this transition is enabled. @@ -1993,7 +2004,7 @@ class DesktopTasksController( } } IndicatorType.TO_SPLIT_LEFT_INDICATOR -> { - handleSnapResizingTask( + handleSnapResizingTaskOnDrag( taskInfo, SnapPosition.LEFT, taskSurface, @@ -2004,7 +2015,7 @@ class DesktopTasksController( ) } IndicatorType.TO_SPLIT_RIGHT_INDICATOR -> { - handleSnapResizingTask( + handleSnapResizingTaskOnDrag( taskInfo, SnapPosition.RIGHT, taskSurface, @@ -2253,31 +2264,6 @@ class DesktopTasksController( taskRepository.dump(pw, innerPrefix) } - override fun handleKeyGestureEvent( - event: KeyGestureEvent, - focusedToken: IBinder? - ): Boolean { - if (!isKeyGestureSupported(event.keyGestureType)) return false - when (event.keyGestureType) { - KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY -> { - if (event.keycodes.contains(KeyEvent.KEYCODE_D) && - event.hasModifiers(KeyEvent.META_CTRL_ON or KeyEvent.META_META_ON)) { - logV("Key gesture MOVE_TO_NEXT_DISPLAY is handled") - getGloballyFocusedFreeformTask()?.let { moveToNextDisplay(it.taskId) } - return true - } - return false - } - else -> return false - } - } - - override fun isKeyGestureSupported(gestureType: Int): Boolean = when (gestureType) { - KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY - -> enableMoveToNextDisplayShortcut() - else -> false - } - /** The interface for calls from outside the shell, within the host process. */ @ExternalThread private inner class DesktopModeImpl : DesktopMode { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java index e848b889b314..2ae9828ca0db 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionHandler.java @@ -254,8 +254,13 @@ public class FreeformTaskTransitionHandler finishT.hide(sc); final Rect startBounds = new Rect(change.getStartAbsBounds()); animator.addUpdateListener(animation -> { - t.setPosition(sc, startBounds.left, - startBounds.top + (animation.getAnimatedFraction() * screenHeight)); + final float newTop = startBounds.top + (animation.getAnimatedFraction() * screenHeight); + t.setPosition(sc, startBounds.left, newTop); + if (newTop > screenHeight) { + // At this point the task surface is off-screen, so hide it to prevent flicker + // failures. See b/377651666. + t.hide(sc); + } t.apply(); }); animator.addListener( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java index b618bf1215ac..319bfac734ba 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/keyguard/KeyguardTransitionHandler.java @@ -42,6 +42,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.ArrayMap; import android.util.Log; +import android.view.Display; import android.view.SurfaceControl; import android.view.WindowManager; import android.window.IRemoteTransition; @@ -54,6 +55,7 @@ import android.window.WindowContainerTransaction; import com.android.internal.protolog.ProtoLog; import com.android.window.flags.Flags; +import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerImpl; @@ -80,6 +82,8 @@ public class KeyguardTransitionHandler private final Transitions mTransitions; private final ShellController mShellController; + + private final DisplayController mDisplayController; private final Handler mMainHandler; private final ShellExecutor mMainExecutor; @@ -121,12 +125,14 @@ public class KeyguardTransitionHandler public KeyguardTransitionHandler( @NonNull ShellInit shellInit, @NonNull ShellController shellController, + @NonNull DisplayController displayController, @NonNull Transitions transitions, @NonNull TaskStackListenerImpl taskStackListener, @NonNull Handler mainHandler, @NonNull ShellExecutor mainExecutor) { mTransitions = transitions; mShellController = shellController; + mDisplayController = displayController; mMainHandler = mainHandler; mMainExecutor = mainExecutor; mTaskStackListener = taskStackListener; @@ -429,10 +435,10 @@ public class KeyguardTransitionHandler @Override public void startKeyguardTransition(boolean keyguardShowing, boolean aodShowing) { final WindowContainerTransaction wct = new WindowContainerTransaction(); - final KeyguardState keyguardState = - new KeyguardState.Builder(android.view.Display.DEFAULT_DISPLAY) - .setKeyguardShowing(keyguardShowing).setAodShowing(aodShowing).build(); - wct.addKeyguardState(keyguardState); + for (Display display : mDisplayController.getDisplays()) { + wct.addKeyguardState(new KeyguardState.Builder(display.getDisplayId()) + .setKeyguardShowing(keyguardShowing).setAodShowing(aodShowing).build()); + } mMainExecutor.execute(() -> { mTransitions.startTransition(keyguardShowing ? TRANSIT_TO_FRONT : TRANSIT_TO_BACK, wct, KeyguardTransitionHandler.this); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java index eb33ff4c1c8e..35c90acd306f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipEnterAnimator.java @@ -52,6 +52,9 @@ public class PipEnterAnimator extends ValueAnimator { private final SurfaceControl.Transaction mStartTransaction; private final SurfaceControl.Transaction mFinishTransaction; + private final int mCornerRadius; + private final int mShadowRadius; + // Bounds updated by the evaluator as animator is running. private final Rect mAnimatedRect = new Rect(); @@ -128,6 +131,8 @@ public class PipEnterAnimator extends ValueAnimator { final int enterAnimationDuration = context.getResources() .getInteger(R.integer.config_pipEnterAnimationDuration); + mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius); + mShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius); setDuration(enterAnimationDuration); setFloatValues(0f, 1f); setInterpolator(Interpolators.FAST_OUT_SLOW_IN); @@ -177,6 +182,8 @@ public class PipEnterAnimator extends ValueAnimator { mTransformTensor.postRotate(degrees); tx.setMatrix(mLeash, mTransformTensor, mMatrixTmp); + tx.setCornerRadius(mLeash, mCornerRadius).setShadowRadius(mLeash, mShadowRadius); + if (mContentOverlay != null) { mContentOverlay.onAnimationUpdate(tx, 1f / scaleX, fraction, mEndBounds); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java index 4558a9f141c8..06e8349259b4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java @@ -29,6 +29,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.annotations.VisibleForTesting; +import com.android.wm.shell.R; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import com.android.wm.shell.shared.animation.Interpolators; @@ -50,6 +51,9 @@ public class PipResizeAnimator extends ValueAnimator { private Runnable mAnimationEndCallback; private RectEvaluator mRectEvaluator; + private final int mCornerRadius; + private final int mShadowRadius; + // Bounds relative to which scaling/cropping must be done. private final Rect mBaseBounds = new Rect(); @@ -74,7 +78,8 @@ public class PipResizeAnimator extends ValueAnimator { mAnimationStartCallback.run(); } if (mStartTx != null) { - setBoundsAndRotation(mStartTx, mLeash, mBaseBounds, mStartBounds, mDelta); + setBoundsAndRotation(mStartTx, mLeash, mBaseBounds, mStartBounds, mDelta, + mCornerRadius, mShadowRadius); mStartTx.apply(); } } @@ -83,7 +88,8 @@ public class PipResizeAnimator extends ValueAnimator { public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); if (mFinishTx != null) { - setBoundsAndRotation(mFinishTx, mLeash, mBaseBounds, mEndBounds, 0f); + setBoundsAndRotation(mFinishTx, mLeash, mBaseBounds, mEndBounds, 0f, + mCornerRadius, mShadowRadius); } if (mAnimationEndCallback != null) { mAnimationEndCallback.run(); @@ -99,7 +105,8 @@ public class PipResizeAnimator extends ValueAnimator { mSurfaceControlTransactionFactory.getTransaction(); final float fraction = getAnimatedFraction(); final float degrees = (1.0f - fraction) * mDelta; - setBoundsAndRotation(tx, mLeash, mBaseBounds, mAnimatedRect, degrees); + setBoundsAndRotation(tx, mLeash, mBaseBounds, mAnimatedRect, degrees, + mCornerRadius, mShadowRadius); tx.apply(); } }; @@ -128,6 +135,9 @@ public class PipResizeAnimator extends ValueAnimator { mRectEvaluator = new RectEvaluator(mAnimatedRect); + mCornerRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius); + mShadowRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius); + setObjectValues(startBounds, endBounds); setInterpolator(Interpolators.FAST_OUT_SLOW_IN); addListener(mAnimatorListener); @@ -152,7 +162,7 @@ public class PipResizeAnimator extends ValueAnimator { * @param degrees degrees of rotation - counter-clockwise is positive by convention. */ private static void setBoundsAndRotation(SurfaceControl.Transaction tx, SurfaceControl leash, - Rect baseBounds, Rect targetBounds, float degrees) { + Rect baseBounds, Rect targetBounds, float degrees, int cornerRadius, int shadowRadius) { Matrix transformTensor = new Matrix(); final float[] mMatrixTmp = new float[9]; final float scaleX = (float) targetBounds.width() / baseBounds.width(); @@ -162,7 +172,9 @@ public class PipResizeAnimator extends ValueAnimator { transformTensor.postTranslate(targetBounds.left, targetBounds.top); transformTensor.postRotate(degrees, targetBounds.centerX(), targetBounds.centerY()); - tx.setMatrix(leash, transformTensor, mMatrixTmp); + tx.setMatrix(leash, transformTensor, mMatrixTmp) + .setCornerRadius(leash, cornerRadius) + .setShadowRadius(leash, shadowRadius); } @VisibleForTesting diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java index e901c39b8792..6d2df952ee58 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java @@ -16,6 +16,7 @@ package com.android.wm.shell.pip2.phone; +import static android.app.WindowConfiguration.ROTATION_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; @@ -293,6 +294,11 @@ public class PipController implements ConfigurationChangeListener, // Update the display layout caches even if we are not in PiP. setDisplayLayout(mDisplayController.getDisplayLayout(displayId)); + if (toRotation != ROTATION_UNDEFINED) { + // Make sure we rotate to final rotation ourselves in case display change is coming + // from the remote rotation as a part of an already collecting transition. + mPipDisplayLayoutState.rotateTo(toRotation); + } if (!mPipTransitionState.isInPip()) { // Skip the PiP-relevant updates if we aren't in a valid PiP state. 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 3738353dd0a3..fd387d1811fb 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 @@ -785,8 +785,16 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private void handleFlingTransition(SurfaceControl.Transaction startTx, SurfaceControl.Transaction finishTx, Rect destinationBounds) { - startTx.setPosition(mPipTransitionState.getPinnedTaskLeash(), - destinationBounds.left, destinationBounds.top); + SurfaceControl pipLeash = mPipTransitionState.getPinnedTaskLeash(); + int cornerRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius); + int shadowRadius = mContext.getResources().getDimensionPixelSize(R.dimen.pip_shadow_radius); + + // merge transactions so everything is done on startTx + startTx.merge(finishTx); + + startTx.setPosition(pipLeash, destinationBounds.left, destinationBounds.top) + .setCornerRadius(pipLeash, cornerRadius) + .setShadowRadius(pipLeash, shadowRadius); startTx.apply(); // All motion operations have actually finished, so make bounds cache updates. 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 d415c10b0cf8..08e672790da6 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 @@ -241,7 +241,7 @@ public class PipTransition extends PipTransitionController implements extra.putParcelable(PIP_TASK_LEASH, pipChange.getLeash()); mPipTransitionState.setState(PipTransitionState.ENTERING_PIP, extra); - if (mPipTransitionState.isInSwipePipToHomeTransition()) { + if (isInSwipePipToHomeTransition()) { // If this is the second transition as a part of swipe PiP to home cuj, // handle this transition as a special case with no-op animation. return handleSwipePipToHomeTransition(info, startTransaction, finishTransaction, @@ -702,6 +702,13 @@ public class PipTransition extends PipTransitionController implements @NonNull TransitionInfo.Change pipChange) { TransitionInfo.Change fixedRotationChange = findFixedRotationChange(info); int startRotation = pipChange.getStartRotation(); + if (pipChange.getEndRotation() != ROTATION_UNDEFINED + && startRotation != pipChange.getEndRotation()) { + // If PiP change was collected along with the display change and the orientation change + // happened in sync with the PiP change, then do not treat this as fixed-rotation case. + return ROTATION_0; + } + int endRotation = fixedRotationChange != null ? fixedRotationChange.getEndFixedRotation() : mPipDisplayLayoutState.getRotation(); int delta = endRotation == ROTATION_UNDEFINED ? ROTATION_0 diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java index 49cf8ae81aa8..35e6c8dd6580 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java @@ -46,6 +46,8 @@ public enum ShellProtoLogGroup implements IProtoLogGroup { "ShellBackPreview"), WM_SHELL_RECENT_TASKS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM_SHELL), + WM_SHELL_TASK_OBSERVER(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, + Consts.TAG_WM_SHELL), // TODO(b/282232877): turn logToLogcat to false. WM_SHELL_PICTURE_IN_PICTURE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true, Consts.TAG_WM_SHELL), diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl index b58f0681c571..68dc0f27bca1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/IRecentTasksListener.aidl @@ -45,9 +45,15 @@ oneway interface IRecentTasksListener { */ void onRunningTaskChanged(in RunningTaskInfo taskInfo); - /** A task has moved to front. */ - void onTaskMovedToFront(in GroupedTaskInfo[] visibleTasks); + /** A task has moved to front. Only used if enableShellTopTaskTracking() is disabled. */ + void onTaskMovedToFront(in GroupedTaskInfo taskToFront); - /** A task info has changed. */ + /** A task info has changed. Only used if enableShellTopTaskTracking() is disabled. */ void onTaskInfoChanged(in RunningTaskInfo taskInfo); + + /** + * If enableShellTopTaskTracking() is enabled, this reports the set of all visible tasks. + * Otherwise, this reports only the new top most visible task. + */ + void onVisibleTasksChanged(in GroupedTaskInfo[] visibleTasks); }
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java index 9911669d2cb8..6da4f510ab77 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java @@ -17,14 +17,18 @@ package com.android.wm.shell.recents; import static android.app.ActivityTaskManager.INVALID_TASK_ID; +import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.content.pm.PackageManager.FEATURE_PC; +import static com.android.wm.shell.Flags.enableShellTopTaskTracking; +import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_OBSERVER; import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_RECENT_TASKS; import android.Manifest; import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.app.ActivityManager.RecentTaskInfo; +import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.app.IApplicationThread; import android.app.KeyguardManager; @@ -65,7 +69,6 @@ import com.android.wm.shell.shared.split.SplitBounds; import com.android.wm.shell.sysui.ShellCommandHandler; import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.sysui.ShellInit; -import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; import java.util.ArrayList; @@ -111,6 +114,11 @@ public class RecentTasksController implements TaskStackListenerCallback, private final Map<Integer, SplitBounds> mTaskSplitBoundsMap = new HashMap<>(); /** + * Cached list of the visible tasks, sorted from top most to bottom most. + */ + private final List<RunningTaskInfo> mVisibleTasks = new ArrayList<>(); + + /** * Creates {@link RecentTasksController}, returns {@code null} if the feature is not * supported. */ @@ -170,10 +178,8 @@ public class RecentTasksController implements TaskStackListenerCallback, mShellCommandHandler.addDumpCallback(this::dump, this); mTaskStackListener.addListener(this); mDesktopRepository.ifPresent(it -> it.addActiveTaskListener(this)); - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this, - mMainExecutor); - } + mTaskStackTransitionObserver.addTaskStackTransitionObserverListener(this, + mMainExecutor); mContext.getSystemService(KeyguardManager.class).addKeyguardLockedStateListener( mMainExecutor, isKeyguardLocked -> notifyRecentTasksChanged()); } @@ -205,7 +211,7 @@ public class RecentTasksController implements TaskStackListenerCallback, mTaskSplitBoundsMap.put(taskId1, splitBounds); mTaskSplitBoundsMap.put(taskId2, splitBounds); notifyRecentTasksChanged(); - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Add split pair: %d, %d, %s", + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Add split pair: %d, %d, %s", taskId1, taskId2, splitBounds); return true; } @@ -221,7 +227,7 @@ public class RecentTasksController implements TaskStackListenerCallback, mTaskSplitBoundsMap.remove(taskId); mTaskSplitBoundsMap.remove(pairedTaskId); notifyRecentTasksChanged(); - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Remove split pair: %d, %d", + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, "Remove split pair: %d, %d", taskId, pairedTaskId); } } @@ -234,7 +240,17 @@ public class RecentTasksController implements TaskStackListenerCallback, // We could do extra verification of requiring both taskIds of a pair and verifying that // the same split bounds object is returned... but meh. Seems unnecessary. - return mTaskSplitBoundsMap.get(taskId); + SplitBounds splitBounds = mTaskSplitBoundsMap.get(taskId); + if (splitBounds != null) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, + "getSplitBoundsForTaskId: taskId=%d splitBoundsTasks=[%d, %d]", taskId, + splitBounds.leftTopTaskId, splitBounds.rightBottomTaskId); + } else { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN, + "getSplitBoundsForTaskId: expected split bounds for taskId=%d but not found", + taskId); + } + return splitBounds; } @Override @@ -249,7 +265,10 @@ public class RecentTasksController implements TaskStackListenerCallback, @Override public void onTaskStackChanged() { - notifyRecentTasksChanged(); + if (!enableShellTopTaskTracking()) { + // Skip notifying recent tasks changed whenever task stack changes + notifyRecentTasksChanged(); + } } @Override @@ -263,15 +282,18 @@ public class RecentTasksController implements TaskStackListenerCallback, notifyRecentTasksChanged(); } - public void onTaskAdded(ActivityManager.RunningTaskInfo taskInfo) { + public void onTaskAdded(RunningTaskInfo taskInfo) { notifyRunningTaskAppeared(taskInfo); } - public void onTaskRemoved(ActivityManager.RunningTaskInfo taskInfo) { + public void onTaskRemoved(RunningTaskInfo taskInfo) { // Remove any split pairs associated with this task removeSplitPair(taskInfo.taskId); - notifyRecentTasksChanged(); notifyRunningTaskVanished(taskInfo); + if (!enableShellTopTaskTracking()) { + // Only notify recent tasks changed if we aren't already notifying the visible tasks + notifyRecentTasksChanged(); + } } /** @@ -279,7 +301,7 @@ public class RecentTasksController implements TaskStackListenerCallback, * * This currently includes windowing mode and visibility. */ - public void onTaskRunningInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { + public void onTaskRunningInfoChanged(RunningTaskInfo taskInfo) { notifyRecentTasksChanged(); notifyRunningTaskChanged(taskInfo); } @@ -290,14 +312,21 @@ public class RecentTasksController implements TaskStackListenerCallback, } @Override + public void onTaskMovedToFrontThroughTransition(RunningTaskInfo runningTaskInfo) { + notifyTaskMovedToFront(runningTaskInfo); + } + + @Override public void onTaskChangedThroughTransition(@NonNull ActivityManager.RunningTaskInfo taskInfo) { notifyTaskInfoChanged(taskInfo); } @Override - public void onTaskMovedToFrontThroughTransition( - ActivityManager.RunningTaskInfo runningTaskInfo) { - notifyTaskMovedToFront(runningTaskInfo); + public void onVisibleTasksChanged(@NonNull List<? extends RunningTaskInfo> visibleTasks) { + mVisibleTasks.clear(); + mVisibleTasks.addAll(visibleTasks); + // Notify with all the info and not just the running task info + notifyVisibleTasksChanged(visibleTasks); } @VisibleForTesting @@ -316,7 +345,7 @@ public class RecentTasksController implements TaskStackListenerCallback, /** * Notify the running task listener that a task appeared on desktop environment. */ - private void notifyRunningTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) { + private void notifyRunningTaskAppeared(RunningTaskInfo taskInfo) { if (mListener == null || !shouldEnableRunningTasksForDesktopMode() || taskInfo.realActivity == null) { @@ -330,9 +359,25 @@ public class RecentTasksController implements TaskStackListenerCallback, } /** + * Notify the running task listener that a task was changed on desktop environment. + */ + private void notifyRunningTaskChanged(RunningTaskInfo taskInfo) { + if (mListener == null + || !shouldEnableRunningTasksForDesktopMode() + || taskInfo.realActivity == null) { + return; + } + try { + mListener.onRunningTaskChanged(taskInfo); + } catch (RemoteException e) { + Slog.w(TAG, "Failed call onRunningTaskChanged", e); + } + } + + /** * Notify the running task listener that a task was removed on desktop environment. */ - private void notifyRunningTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { + private void notifyRunningTaskVanished(RunningTaskInfo taskInfo) { if (mListener == null || !shouldEnableRunningTasksForDesktopMode() || taskInfo.realActivity == null) { @@ -346,25 +391,30 @@ public class RecentTasksController implements TaskStackListenerCallback, } /** - * Notify the running task listener that a task was changed on desktop environment. + * Notify the recents task listener that a task moved to front via a transition. */ - private void notifyRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) { + private void notifyTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) { if (mListener == null - || !shouldEnableRunningTasksForDesktopMode() - || taskInfo.realActivity == null) { + || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue() + || taskInfo.realActivity == null + || enableShellTopTaskTracking()) { return; } try { - mListener.onRunningTaskChanged(taskInfo); + mListener.onTaskMovedToFront(GroupedTaskInfo.forFullscreenTasks(taskInfo)); } catch (RemoteException e) { - Slog.w(TAG, "Failed call onRunningTaskChanged", e); + Slog.w(TAG, "Failed call onTaskMovedToFront", e); } } + /** + * Notify the recents task listener that a task changed via a transition. + */ private void notifyTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { if (mListener == null || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue() - || taskInfo.realActivity == null) { + || taskInfo.realActivity == null + || enableShellTopTaskTracking()) { return; } try { @@ -374,17 +424,21 @@ public class RecentTasksController implements TaskStackListenerCallback, } } - private void notifyTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) { + /** + * Notifies that the test of visible tasks have changed. + */ + private void notifyVisibleTasksChanged(@NonNull List<? extends RunningTaskInfo> visibleTasks) { if (mListener == null || !DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue() - || taskInfo.realActivity == null) { + || !enableShellTopTaskTracking()) { return; } try { - GroupedTaskInfo runningTask = GroupedTaskInfo.forFullscreenTasks(taskInfo); - mListener.onTaskMovedToFront(new GroupedTaskInfo[]{ runningTask }); + // Compute the visible recent tasks in order, and move the task to the top + mListener.onVisibleTasksChanged(generateList(visibleTasks) + .toArray(new GroupedTaskInfo[0])); } catch (RemoteException e) { - Slog.w(TAG, "Failed call onTaskMovedToFront", e); + Slog.w(TAG, "Failed call onVisibleTasksChanged", e); } } @@ -397,6 +451,11 @@ public class RecentTasksController implements TaskStackListenerCallback, @VisibleForTesting void registerRecentTasksListener(IRecentTasksListener listener) { mListener = listener; + if (enableShellTopTaskTracking()) { + ProtoLog.v(WM_SHELL_TASK_OBSERVER, "registerRecentTasksListener"); + // Post a notification for the current set of visible tasks + mMainExecutor.executeDelayed(() -> notifyVisibleTasksChanged(mVisibleTasks), 0); + } } @VisibleForTesting @@ -411,14 +470,18 @@ public class RecentTasksController implements TaskStackListenerCallback, @VisibleForTesting ArrayList<GroupedTaskInfo> getRecentTasks(int maxNum, int flags, int userId) { - // Note: the returned task list is from the most-recent to least-recent order - final List<RecentTaskInfo> rawList = mActivityTaskManager.getRecentTasks( - maxNum, flags, userId); + // Note: the returned task list is ordered from the most-recent to least-recent order + return generateList(mActivityTaskManager.getRecentTasks(maxNum, flags, userId)); + } + /** + * Generates a list of GroupedTaskInfos for the given list of tasks. + */ + private <T extends TaskInfo> ArrayList<GroupedTaskInfo> generateList(@NonNull List<T> tasks) { // Make a mapping of task id -> task info final SparseArray<TaskInfo> rawMapping = new SparseArray<>(); - for (int i = 0; i < rawList.size(); i++) { - final TaskInfo taskInfo = rawList.get(i); + for (int i = 0; i < tasks.size(); i++) { + final TaskInfo taskInfo = tasks.get(i); rawMapping.put(taskInfo.taskId, taskInfo); } @@ -427,10 +490,10 @@ public class RecentTasksController implements TaskStackListenerCallback, int mostRecentFreeformTaskIndex = Integer.MAX_VALUE; + ArrayList<GroupedTaskInfo> groupedTasks = new ArrayList<>(); // Pull out the pairs as we iterate back in the list - ArrayList<GroupedTaskInfo> recentTasks = new ArrayList<>(); - for (int i = 0; i < rawList.size(); i++) { - final RecentTaskInfo taskInfo = rawList.get(i); + for (int i = 0; i < tasks.size(); i++) { + final TaskInfo taskInfo = tasks.get(i); if (!rawMapping.contains(taskInfo.taskId)) { // If it's not in the mapping, then it was already paired with another task continue; @@ -441,7 +504,7 @@ public class RecentTasksController implements TaskStackListenerCallback, && mDesktopRepository.get().isActiveTask(taskInfo.taskId)) { // Freeform tasks will be added as a separate entry if (mostRecentFreeformTaskIndex == Integer.MAX_VALUE) { - mostRecentFreeformTaskIndex = recentTasks.size(); + mostRecentFreeformTaskIndex = groupedTasks.size(); } // If task has their app bounds set to null which happens after reboot, set the // app bounds to persisted lastFullscreenBounds. Also set the position in parent @@ -461,36 +524,34 @@ public class RecentTasksController implements TaskStackListenerCallback, } final int pairedTaskId = mSplitTasks.get(taskInfo.taskId, INVALID_TASK_ID); - if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains( - pairedTaskId)) { + if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains(pairedTaskId)) { final TaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId); rawMapping.remove(pairedTaskId); - recentTasks.add(GroupedTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo, + groupedTasks.add(GroupedTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo, mTaskSplitBoundsMap.get(pairedTaskId))); } else { - recentTasks.add(GroupedTaskInfo.forFullscreenTasks(taskInfo)); + // TODO(346588978): Consolidate multiple visible fullscreen tasks into the same + // grouped task + groupedTasks.add(GroupedTaskInfo.forFullscreenTasks(taskInfo)); } } // Add a special entry for freeform tasks if (!freeformTasks.isEmpty()) { - recentTasks.add(mostRecentFreeformTaskIndex, + groupedTasks.add(mostRecentFreeformTaskIndex, GroupedTaskInfo.forFreeformTasks( freeformTasks, minimizedFreeformTasks)); } - return recentTasks; - } + if (enableShellTopTaskTracking()) { + // We don't current send pinned tasks as a part of recent or running tasks, so remove + // them from the list here + groupedTasks.removeIf( + gti -> gti.getTaskInfo1().getWindowingMode() == WINDOWING_MODE_PINNED); + } - /** - * Returns the top running leaf task. - */ - @Nullable - public ActivityManager.RunningTaskInfo getTopRunningTask() { - List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(1, - false /* filterOnlyVisibleRecents */); - return tasks.isEmpty() ? null : tasks.get(0); + return groupedTasks; } /** @@ -498,12 +559,13 @@ public class RecentTasksController implements TaskStackListenerCallback, * NOTE: This path currently makes assumptions that ignoreTaskToken is for the top task. */ @Nullable - public ActivityManager.RunningTaskInfo getTopRunningTask( + public RunningTaskInfo getTopRunningTask( @Nullable WindowContainerToken ignoreTaskToken) { - List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(2, - false /* filterOnlyVisibleRecents */); + final List<RunningTaskInfo> tasks = enableShellTopTaskTracking() + ? mVisibleTasks + : mActivityTaskManager.getTasks(2, false /* filterOnlyVisibleRecents */); for (int i = 0; i < tasks.size(); i++) { - final ActivityManager.RunningTaskInfo task = tasks.get(i); + final RunningTaskInfo task = tasks.get(i); if (task.token.equals(ignoreTaskToken)) { continue; } @@ -541,7 +603,7 @@ public class RecentTasksController implements TaskStackListenerCallback, } /** - * Find the background task that match the given taskId. + * Find the background task (in the recent tasks list) that matches the given taskId. */ @Nullable public RecentTaskInfo findTaskInBackground(int taskId) { @@ -638,29 +700,34 @@ public class RecentTasksController implements TaskStackListenerCallback, } @Override - public void onRunningTaskAppeared(ActivityManager.RunningTaskInfo taskInfo) { + public void onRunningTaskAppeared(RunningTaskInfo taskInfo) { mListener.call(l -> l.onRunningTaskAppeared(taskInfo)); } @Override - public void onRunningTaskVanished(ActivityManager.RunningTaskInfo taskInfo) { + public void onRunningTaskVanished(RunningTaskInfo taskInfo) { mListener.call(l -> l.onRunningTaskVanished(taskInfo)); } @Override - public void onRunningTaskChanged(ActivityManager.RunningTaskInfo taskInfo) { + public void onRunningTaskChanged(RunningTaskInfo taskInfo) { mListener.call(l -> l.onRunningTaskChanged(taskInfo)); } @Override - public void onTaskMovedToFront(GroupedTaskInfo[] taskInfo) { - mListener.call(l -> l.onTaskMovedToFront(taskInfo)); + public void onTaskMovedToFront(GroupedTaskInfo taskToFront) { + mListener.call(l -> l.onTaskMovedToFront(taskToFront)); } @Override public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) { mListener.call(l -> l.onTaskInfoChanged(taskInfo)); } + + @Override + public void onVisibleTasksChanged(GroupedTaskInfo[] visibleTasks) { + mListener.call(l -> l.onVisibleTasksChanged(visibleTasks)); + } }; public IRecentTasksImpl(RecentTasksController controller) { @@ -714,12 +781,12 @@ public class RecentTasksController implements TaskStackListenerCallback, } @Override - public ActivityManager.RunningTaskInfo[] getRunningTasks(int maxNum) { - final ActivityManager.RunningTaskInfo[][] tasks = - new ActivityManager.RunningTaskInfo[][]{null}; + public RunningTaskInfo[] getRunningTasks(int maxNum) { + final RunningTaskInfo[][] tasks = + new RunningTaskInfo[][]{null}; executeRemoteCallWithTaskPermission(mController, "getRunningTasks", (controller) -> tasks[0] = ActivityTaskManager.getInstance().getTasks(maxNum) - .toArray(new ActivityManager.RunningTaskInfo[0]), + .toArray(new RunningTaskInfo[0]), true /* blocking */); return tasks[0]; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java index 417a6558ffcc..1c58dbbf71fd 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java @@ -1308,6 +1308,9 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler, // otherwise a new transition will notify the relevant observers if (returningToApp && allAppsAreTranslucent(mPausingTasks)) { mHomeTransitionObserver.notifyHomeVisibilityChanged(true); + } else if (!toHome && mState == STATE_NEW_TASK + && allAppsAreTranslucent(mOpeningTasks)) { + // We are opening a translucent app. Launcher is still visible so we do nothing. } else if (!toHome) { // For some transitions, we may have notified home activity that it became // visible. We need to notify the observer that we are no longer going home. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt index d28a462546f9..93f2e4cf0e45 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/TaskStackTransitionObserver.kt @@ -17,37 +17,162 @@ package com.android.wm.shell.recents import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.WINDOWING_MODE_PINNED import android.os.IBinder import android.util.ArrayMap import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CHANGE import android.window.DesktopModeFlags import android.window.TransitionInfo +import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.Flags.enableShellTopTaskTracking +import com.android.wm.shell.ShellTaskOrganizer +import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_OBSERVER import com.android.wm.shell.shared.TransitionUtil +import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions import dagger.Lazy +import java.io.PrintWriter +import java.util.StringJoiner import java.util.concurrent.Executor /** - * A [Transitions.TransitionObserver] that observes shell transitions and sends updates to listeners - * about task stack changes. + * A [Transitions.TransitionObserver] that observes shell transitions, tracks the visible tasks + * and notifies listeners whenever the visible tasks change (at the start and end of a transition). * - * TODO(346588978) Move split/pip signals here as well so that launcher don't need to handle it + * This can be replaced once we have a generalized task repository tracking visible tasks. */ class TaskStackTransitionObserver( + shellInit: ShellInit, + private val shellTaskOrganizer: Lazy<ShellTaskOrganizer>, + private val shellCommandHandler: ShellCommandHandler, private val transitions: Lazy<Transitions>, - shellInit: ShellInit -) : Transitions.TransitionObserver { +) : Transitions.TransitionObserver, ShellTaskOrganizer.TaskVanishedListener { + + // List of currently visible tasks sorted in z-order from top-most to bottom-most, only used + // when Flags.enableShellTopTaskTracking() is enabled. + private var visibleTasks: MutableList<RunningTaskInfo> = mutableListOf() + private val pendingCloseTasks: MutableList<RunningTaskInfo> = mutableListOf() + // Set of listeners to notify when the visible tasks change private val taskStackTransitionObserverListeners = ArrayMap<TaskStackTransitionObserverListener, Executor>() + // Used to filter out leaf-tasks + private val leafTaskFilter: TransitionUtil.LeafTaskFilter = TransitionUtil.LeafTaskFilter() init { shellInit.addInitCallback(::onInit, this) } fun onInit() { + shellTaskOrganizer.get().addTaskVanishedListener(this) + shellCommandHandler.addDumpCallback(::dump, this) transitions.get().registerObserver(this) + + // TODO(346588978): We need to update the running tasks once the ShellTaskOrganizer is + // registered since there is no existing transition (yet) corresponding for the already + // visible tasks + } + + /** + * This method handles transition ready when only + * DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL is set. + */ + private fun onDesktopOnlyFlagTransitionReady(info: TransitionInfo) { + for (change in info.changes) { + if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) { + continue + } + + val taskInfo = change.taskInfo + if (taskInfo == null || taskInfo.taskId == -1) { + continue + } + + // Find the first task that is opening, this should be the one at the front after + // the transition + if (TransitionUtil.isOpeningType(change.mode)) { + notifyOnTaskMovedToFront(taskInfo) + break + } else if (change.mode == TRANSIT_CHANGE) { + notifyOnTaskChanged(taskInfo) + } + } + } + + /** + * This method handles transition ready when Flags.enableShellTopTaskTracking() is set. + */ + private fun onShellTopTaskTrackerFlagTransitionReady(info: TransitionInfo) { + ProtoLog.v(WM_SHELL_TASK_OBSERVER, "Transition ready: %d", info.debugId) + + // Filter out non-leaf tasks (we will likely need them later, but visible task tracking + // is currently used only for visible leaf tasks) + val changesReversed = mutableListOf<TransitionInfo.Change>() + for (change in info.changes) { + if (!leafTaskFilter.test(change)) { + // Not a leaf task + continue + } + changesReversed.add(0, change) + } + + // We iterate the change list in reverse order because changes are sorted top to bottom and + // we want to update the lists such that the top most tasks are inserted at the front last + var notifyChanges = false + for (change in changesReversed) { + val taskInfo = change.taskInfo + if (taskInfo == null || taskInfo.taskId == -1) { + // Not a valid task + continue + } + + if (TransitionUtil.isClosingMode(change.mode)) { + ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\tClosing task=%d", taskInfo.taskId) + + // Closing task's visibilities are not committed until after the transition + // completes, so track such tasks so that we can notify on finish + if (!pendingCloseTasks.any { it.taskId == taskInfo.taskId }) { + pendingCloseTasks.add(taskInfo) + } + } else if (TransitionUtil.isOpeningMode(change.mode) + || TransitionUtil.isOrderOnly(change)) { + ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\tOpening task=%d", taskInfo.taskId) + + // Remove from pending close tasks list if it's being opened again + pendingCloseTasks.removeIf { it.taskId == taskInfo.taskId } + // Move the task to the front of the visible tasks list + visibleTasks.removeIf { it.taskId == taskInfo.taskId } + visibleTasks.add(0, taskInfo) + notifyChanges = true + } + } + + // TODO(346588978): We should verify the task list has actually changed before notifying + // (ie. starting an activity that's already top-most would result in no visible change) + if (notifyChanges) { + updateVisibleTasksList("transition-start") + } + } + + private fun updateVisibleTasksList(reason: String) { + // This simply constructs a list of visible tasks, where the always-on-top tasks are moved + // to the front of the list in-order, to ensure that they match the visible z order + val orderedVisibleTasks = mutableListOf<RunningTaskInfo>() + var numAlwaysOnTop = 0 + for (info in visibleTasks) { + if (info.windowingMode == WINDOWING_MODE_PINNED + || info.configuration.windowConfiguration.isAlwaysOnTop) { + orderedVisibleTasks.add(numAlwaysOnTop, info) + numAlwaysOnTop++ + } else { + orderedVisibleTasks.add(info) + } + } + visibleTasks = orderedVisibleTasks + + dumpVisibleTasks(reason) + notifyVisibleTasksChanged(visibleTasks) } override fun onTransitionReady( @@ -56,26 +181,10 @@ class TaskStackTransitionObserver( startTransaction: SurfaceControl.Transaction, finishTransaction: SurfaceControl.Transaction ) { - if (DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue) { - for (change in info.changes) { - if (change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0) { - continue - } - - val taskInfo = change.taskInfo - if (taskInfo == null || taskInfo.taskId == -1) { - continue - } - - // Find the first task that is opening, this should be the one at the front after - // the transition - if (TransitionUtil.isOpeningType(change.mode)) { - notifyOnTaskMovedToFront(taskInfo) - break - } else if (change.mode == TRANSIT_CHANGE) { - notifyOnTaskChanged(taskInfo) - } - } + if (enableShellTopTaskTracking()) { + onShellTopTaskTrackerFlagTransitionReady(info) + } else if (DesktopModeFlags.ENABLE_TASK_STACK_OBSERVER_IN_SHELL.isTrue) { + onDesktopOnlyFlagTransitionReady(info) } } @@ -83,8 +192,35 @@ class TaskStackTransitionObserver( override fun onTransitionMerged(merged: IBinder, playing: IBinder) {} - override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {} + override fun onTransitionFinished(transition: IBinder, aborted: Boolean) { + if (enableShellTopTaskTracking()) { + if (pendingCloseTasks.isNotEmpty()) { + // Update the visible task list based on the pending close tasks + for (change in pendingCloseTasks) { + visibleTasks.removeIf { + it.taskId == change.taskId + } + } + updateVisibleTasksList("transition-finished") + } + } + } + override fun onTaskVanished(taskInfo: RunningTaskInfo?) { + if (!enableShellTopTaskTracking()) { + return + } + ProtoLog.v(WM_SHELL_TASK_OBSERVER, "Task vanished: task=%d", taskInfo?.taskId) + pendingCloseTasks.removeIf { it.taskId == taskInfo?.taskId } + if (visibleTasks.any { it.taskId == taskInfo?.taskId }) { + visibleTasks.removeIf { it.taskId == taskInfo?.taskId } + updateVisibleTasksList("task-vanished") + } + } + + /** + * Adds a new task stack observer. + */ fun addTaskStackTransitionObserverListener( taskStackTransitionObserverListener: TaskStackTransitionObserverListener, executor: Executor @@ -92,6 +228,9 @@ class TaskStackTransitionObserver( taskStackTransitionObserverListeners[taskStackTransitionObserverListener] = executor } + /** + * Removes an existing task stack observer. + */ fun removeTaskStackTransitionObserverListener( taskStackTransitionObserverListener: TaskStackTransitionObserverListener ) { @@ -99,22 +238,66 @@ class TaskStackTransitionObserver( } private fun notifyOnTaskMovedToFront(taskInfo: RunningTaskInfo) { + if (enableShellTopTaskTracking()) { + return + } taskStackTransitionObserverListeners.forEach { (listener, executor) -> executor.execute { listener.onTaskMovedToFrontThroughTransition(taskInfo) } } } private fun notifyOnTaskChanged(taskInfo: RunningTaskInfo) { + if (enableShellTopTaskTracking()) { + return + } taskStackTransitionObserverListeners.forEach { (listener, executor) -> executor.execute { listener.onTaskChangedThroughTransition(taskInfo) } } } + private fun notifyVisibleTasksChanged(visibleTasks: List<RunningTaskInfo>) { + taskStackTransitionObserverListeners.forEach { (listener, executor) -> + executor.execute { listener.onVisibleTasksChanged(visibleTasks) } + } + } + + fun dump(pw: PrintWriter, prefix: String) { + pw.println("${prefix}$TAG:") + + if (visibleTasks.isEmpty()) { + pw.println("$prefix visibleTasks=[]") + } else { + val stringJoiner = StringJoiner(",\n\t", "[\n\t", "\n]") + visibleTasks.forEach { + stringJoiner.add("id=${it.taskId} cmp=${it.baseIntent.component}") + } + pw.println("$prefix visibleTasks=$stringJoiner") + } + } + + /** Dumps the set of visible tasks to protolog */ + private fun dumpVisibleTasks(reason: String) { + if (!WM_SHELL_TASK_OBSERVER.isEnabled) { + return + } + ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\tVisible tasks (%s)", reason) + for (task in visibleTasks) { + ProtoLog.v(WM_SHELL_TASK_OBSERVER, "\t\ttaskId=%d package=%s", task.taskId, + task.baseIntent.component?.packageName) + } + } + /** Listener to use to get updates regarding task stack from this observer */ interface TaskStackTransitionObserverListener { /** Called when a task is moved to front. */ fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) {} + /** Called when the set of visible tasks have changed. */ + fun onVisibleTasksChanged(visibleTasks: List<RunningTaskInfo>) {} /** Called when a task info has changed. */ fun onTaskChangedThroughTransition(taskInfo: RunningTaskInfo) {} } + + companion object { + const val TAG = "TaskStackTransitionObserver" + } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java index cc0e1df115c2..e692c61cd493 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java @@ -55,7 +55,6 @@ import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE; import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_UNDEFINED; import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_LAUNCHER; -import static com.android.wm.shell.splitscreen.SplitScreenController.ENTER_REASON_MULTI_INSTANCE; import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW; import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_FINISHED; import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_CHILD_TASK_ENTER_PIP; @@ -1099,16 +1098,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, void setSideStagePosition(@SplitPosition int sideStagePosition, @Nullable WindowContainerTransaction wct) { - setSideStagePosition(sideStagePosition, true /* updateBounds */, wct); - } - - private void setSideStagePosition(@SplitPosition int sideStagePosition, boolean updateBounds, - @Nullable WindowContainerTransaction wct) { if (mSideStagePosition == sideStagePosition) return; mSideStagePosition = sideStagePosition; sendOnStagePositionChanged(); - if (mSideStage.mVisible && updateBounds) { + if (mSideStage.mVisible) { if (wct == null) { // onLayoutChanged builds/applies a wct with the contents of updateWindowBounds. onLayoutSizeChanged(mSplitLayout); @@ -1275,6 +1269,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, final WindowContainerTransaction wct = new WindowContainerTransaction(); prepareExitSplitScreen(stage, wct); mSplitTransitions.startDismissTransition(wct, this, stage, exitReason); + // reset stages to their default sides. + setSideStagePosition(SPLIT_POSITION_BOTTOM_OR_RIGHT, null); logExit(exitReason); } @@ -1362,7 +1358,11 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } void clearSplitPairedInRecents(@ExitReason int exitReason) { - if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) return; + if (!shouldBreakPairedTaskInRecents(exitReason) || !mShouldUpdateRecents) { + ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "clearSplitPairedInRecents: skipping reason=%s", + !mShouldUpdateRecents ? "shouldn't update" : exitReasonToString(exitReason)); + return; + } ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "clearSplitPairedInRecents: reason=%s", exitReasonToString(exitReason)); @@ -1598,6 +1598,13 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, } if (present) { updateRecentTasksSplitPair(); + } else if (mMainStage.getChildCount() == 0 && mSideStage.getChildCount() == 0) { + mRecentTasks.ifPresent(recentTasks -> { + // remove the split pair mapping from recentTasks, and disable further updates + // to splits in the recents until we enter split again. + recentTasks.removeSplitPair(taskId); + }); + dismissSplitScreen(-1, EXIT_REASON_ROOT_TASK_VANISHED); } for (int i = mListeners.size() - 1; i >= 0; --i) { @@ -1608,6 +1615,8 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, private void updateRecentTasksSplitPair() { // Preventing from single task update while processing recents. if (!mShouldUpdateRecents || !mPausingTasks.isEmpty()) { + ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "updateRecentTasksSplitPair: skipping reason=%s", + !mShouldUpdateRecents ? "shouldn't update" : "no pausing tasks"); return; } mRecentTasks.ifPresent(recentTasks -> { @@ -3182,9 +3191,9 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler, for (int i = mPausingTasks.size() - 1; i >= 0; --i) { final int taskId = mPausingTasks.get(i); if (mMainStage.containsTask(taskId)) { - mMainStage.evictChildren(finishWct, taskId); + mMainStage.evictChild(finishWct, taskId, "recentsPairToPair"); } else if (mSideStage.containsTask(taskId)) { - mSideStage.evictChildren(finishWct, taskId); + mSideStage.evictChild(finishWct, taskId, "recentsPairToPair"); } } // If pending enter hasn't consumed, the mix handler will invoke start pending diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java index 4407e5b3106f..08cdfdb3b5a9 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java @@ -30,6 +30,7 @@ import static com.android.wm.shell.shared.split.SplitScreenConstants.CONTROLLED_ import android.annotation.CallSuper; import android.annotation.Nullable; import android.app.ActivityManager; +import android.app.TaskInfo; import android.content.Context; import android.graphics.Rect; import android.os.IBinder; @@ -138,6 +139,8 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener { * Returns the top visible child task's id. */ int getTopVisibleChildTaskId() { + // TODO(b/378601156): This doesn't get the top task (translucent tasks are also + // visible-requested) final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.isVisible && t.isVisibleRequested); return taskInfo != null ? taskInfo.taskId : INVALID_TASK_ID; @@ -147,6 +150,7 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener { * Returns the top activity uid for the top child task. */ int getTopChildTaskUid() { + // TODO(b/378601156): This doesn't get the top task final ActivityManager.RunningTaskInfo taskInfo = getChildTaskInfo(t -> t.topActivityInfo != null); return taskInfo != null ? taskInfo.topActivityInfo.applicationInfo.uid : 0; @@ -379,10 +383,9 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener { /** Collects all the current child tasks and prepares transaction to evict them to display. */ void evictAllChildren(WindowContainerTransaction wct) { - ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evicting all children"); for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); - wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); + evictChild(wct, taskInfo, "all"); } } @@ -390,13 +393,11 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); if (taskId == taskInfo.taskId) continue; - ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict other child: task=%d", taskId); - wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); + evictChild(wct, taskInfo, "other"); } } void evictNonOpeningChildren(RemoteAnimationTarget[] apps, WindowContainerTransaction wct) { - ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "evictNonOpeningChildren"); final SparseArray<ActivityManager.RunningTaskInfo> toBeEvict = mChildrenTaskInfo.clone(); for (int i = 0; i < apps.length; i++) { if (apps[i].mode == MODE_OPENING) { @@ -405,8 +406,7 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener { } for (int i = toBeEvict.size() - 1; i >= 0; i--) { final ActivityManager.RunningTaskInfo taskInfo = toBeEvict.valueAt(i); - ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict non-opening child: task=%d", taskInfo.taskId); - wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); + evictChild(wct, taskInfo, "non-opening"); } } @@ -414,21 +414,30 @@ public class StageTaskListener implements ShellTaskOrganizer.TaskListener { for (int i = mChildrenTaskInfo.size() - 1; i >= 0; i--) { final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.valueAt(i); if (!taskInfo.isVisible) { - ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict invisible child: task=%d", - taskInfo.taskId); - wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); + evictChild(wct, taskInfo, "invisible"); } } } - void evictChildren(WindowContainerTransaction wct, int taskId) { - ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict child: task=%d", taskId); + void evictChild(WindowContainerTransaction wct, int taskId, String reason) { final ActivityManager.RunningTaskInfo taskInfo = mChildrenTaskInfo.get(taskId); if (taskInfo != null) { - wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); + evictChild(wct, taskInfo, reason); } } + private void evictChild(@NonNull WindowContainerTransaction wct, @NonNull TaskInfo taskInfo, + @NonNull String reason) { + ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Evict child: task=%d reason=%s", taskInfo.taskId, + reason); + // We are reparenting the task, but not removing the task from mChildrenTaskInfo, so to + // prevent this task from being considered as a top task for the roots, we need to override + // the visibility of the soon-to-be-hidden task + taskInfo.isVisible = false; + taskInfo.isVisibleRequested = false; + wct.reparent(taskInfo.token, null /* parent */, false /* onTop */); + } + void reparentTopTask(WindowContainerTransaction wct) { wct.reparentTasks(null /* currentParent */, mRootTaskInfo.token, CONTROLLED_WINDOWING_MODES, CONTROLLED_ACTIVITY_TYPES, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index d71e61a4c4de..f89b0d108bad 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -78,7 +78,6 @@ import android.view.SurfaceControl; import android.view.SurfaceControl.Transaction; import android.view.View; import android.view.ViewConfiguration; -import android.widget.Toast; import android.window.DesktopModeFlags; import android.window.TaskSnapshot; import android.window.WindowContainerToken; @@ -572,9 +571,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, if (decoration == null) { return; } - mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent, - decoration.mTaskInfo, - mDisplayController, /* displayLayoutSize= */ null); mInteractionJankMonitor.begin( decoration.mTaskSurface, mContext, mMainHandler, Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW, source); @@ -593,33 +589,20 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel, decoration.closeMaximizeMenu(); } - private void onSnapResize(int taskId, boolean left, MotionEvent motionEvent) { + public void onSnapResize(int taskId, boolean left, @Nullable MotionEvent motionEvent) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } - if (!decoration.mTaskInfo.isResizeable - && DesktopModeFlags.DISABLE_NON_RESIZABLE_APP_SNAP_RESIZE.isTrue()) { - Toast.makeText(mContext, - R.string.desktop_mode_non_resizable_snap_text, Toast.LENGTH_SHORT).show(); - } else { - ResizeTrigger resizeTrigger = - left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU; - mDesktopModeEventLogger.logTaskResizingStarted(resizeTrigger, motionEvent, - decoration.mTaskInfo, - mDisplayController, /* displayLayoutSize= */ null); - mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler, - Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable"); - mDesktopTasksController.snapToHalfScreen( - decoration.mTaskInfo, - decoration.mTaskSurface, - decoration.mTaskInfo.configuration.windowConfiguration.getBounds(), - left ? SnapPosition.LEFT : SnapPosition.RIGHT, - resizeTrigger, - motionEvent, - mWindowDecorByTaskId.get(taskId)); - } + mInteractionJankMonitor.begin(decoration.mTaskSurface, mContext, mMainHandler, + Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE, "maximize_menu_resizable"); + mDesktopTasksController.handleInstantSnapResizingTask( + decoration.mTaskInfo, + left ? SnapPosition.LEFT : SnapPosition.RIGHT, + left ? ResizeTrigger.SNAP_LEFT_MENU : ResizeTrigger.SNAP_RIGHT_MENU, + motionEvent, + decoration); decoration.closeHandleMenu(); decoration.closeMaximizeMenu(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index cdcf14e0cbf3..723bbd318803 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -81,7 +81,6 @@ import android.window.TaskSnapshot; import android.window.WindowContainerTransaction; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.policy.ScreenDecorationsUtils; import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.IconProvider; import com.android.window.flags.Flags; @@ -207,7 +206,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private final WindowDecorCaptionHandleRepository mWindowDecorCaptionHandleRepository; private final DesktopRepository mDesktopRepository; - DesktopModeWindowDecoration( + public DesktopModeWindowDecoration( Context context, @NonNull Context userContext, DisplayController displayController, @@ -1008,8 +1007,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin relayoutParams.mWindowDecorConfig = windowDecorConfig; if (DesktopModeStatus.useRoundedCorners()) { - relayoutParams.mCornerRadius = - (int) ScreenDecorationsUtils.getWindowCornerRadius(context); + relayoutParams.mCornerRadius = taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM + ? loadDimensionPixelSize(context.getResources(), + R.dimen.desktop_windowing_freeform_rounded_corner_radius) + : INVALID_CORNER_RADIUS; } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt index 54c247bff984..62be2c78d59b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt @@ -238,8 +238,12 @@ class HandleMenu( val taskBounds = taskInfo.getConfiguration().windowConfiguration.bounds updateGlobalMenuPosition(taskBounds, captionX, captionY) if (layoutResId == R.layout.desktop_mode_app_header) { - // Align the handle menu to the left side of the caption. - menuX = marginMenuStart + // Align the handle menu to the start of the header. + menuX = if (context.isRtl()) { + taskBounds.width() - menuWidth - marginMenuStart + } else { + marginMenuStart + } menuY = captionY + marginMenuTop } else { if (DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue()) { @@ -261,10 +265,17 @@ class HandleMenu( val nonFreeformX = captionX + (captionWidth / 2) - (menuWidth / 2) when { taskInfo.isFreeform -> { - globalMenuPosition.set( - /* x = */ taskBounds.left + marginMenuStart, - /* y = */ taskBounds.top + captionY + marginMenuTop - ) + if (context.isRtl()) { + globalMenuPosition.set( + /* x= */ taskBounds.right - menuWidth - marginMenuStart, + /* y= */ taskBounds.top + captionY + marginMenuTop + ) + } else { + globalMenuPosition.set( + /* x= */ taskBounds.left + marginMenuStart, + /* y= */ taskBounds.top + captionY + marginMenuTop + ) + } } taskInfo.isFullscreen -> { globalMenuPosition.set( @@ -430,6 +441,9 @@ class HandleMenu( return context.resources.getDimensionPixelSize(resourceId) } + private fun Context.isRtl() = + resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL + fun close() { handleMenuView?.animateCloseMenu { handleMenuViewContainer?.releaseView() diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index a3c75bf33cde..852eee5f6672 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -107,6 +107,11 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> static final int INPUT_SINK_Z_ORDER = -2; /** + * Invalid corner radius that signifies that corner radius should not be set. + */ + static final int INVALID_CORNER_RADIUS = -1; + + /** * System-wide context. Only used to create context with overridden configurations. */ final Context mContext; @@ -449,20 +454,22 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> startT.show(mTaskSurface); } - if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) { - if (!DesktopModeStatus.isVeiledResizeEnabled()) { - // When fluid resize is enabled, add a background to freeform tasks - int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor(); - mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; - mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; - mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; - startT.setColor(mTaskSurface, mTmpColor); - } - startT.setCornerRadius(mTaskSurface, params.mCornerRadius); - finishT.setCornerRadius(mTaskSurface, params.mCornerRadius); + if (mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM + && !DesktopModeStatus.isVeiledResizeEnabled()) { + // When fluid resize is enabled, add a background to freeform tasks + int backgroundColorInt = mTaskInfo.taskDescription.getBackgroundColor(); + mTmpColor[0] = (float) Color.red(backgroundColorInt) / 255.f; + mTmpColor[1] = (float) Color.green(backgroundColorInt) / 255.f; + mTmpColor[2] = (float) Color.blue(backgroundColorInt) / 255.f; + startT.setColor(mTaskSurface, mTmpColor); } else if (!DesktopModeStatus.isVeiledResizeEnabled()) { startT.unsetColor(mTaskSurface); } + + if (params.mCornerRadius != INVALID_CORNER_RADIUS) { + startT.setCornerRadius(mTaskSurface, params.mCornerRadius); + finishT.setCornerRadius(mTaskSurface, params.mCornerRadius); + } } /** @@ -593,13 +600,25 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> private Rect calculateBoundingRectLocal(@NonNull OccludingCaptionElement element, int elementWidthPx, @NonNull Rect captionRect) { + final boolean isRtl = + mDecorWindowContext.getResources().getConfiguration().getLayoutDirection() + == View.LAYOUT_DIRECTION_RTL; switch (element.mAlignment) { case START -> { - return new Rect(0, 0, elementWidthPx, captionRect.height()); + if (isRtl) { + return new Rect(captionRect.width() - elementWidthPx, 0, + captionRect.width(), captionRect.height()); + } else { + return new Rect(0, 0, elementWidthPx, captionRect.height()); + } } case END -> { - return new Rect(captionRect.width() - elementWidthPx, 0, - captionRect.width(), captionRect.height()); + if (isRtl) { + return new Rect(0, 0, elementWidthPx, captionRect.height()); + } else { + return new Rect(captionRect.width() - elementWidthPx, 0, + captionRect.width(), captionRect.height()); + } } } throw new IllegalArgumentException("Unexpected alignment " + element.mAlignment); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt index 503ad92d4d71..5f25f42039ef 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt @@ -114,7 +114,7 @@ internal class AppHandleViewHolder( // If handle is not in status bar region(i.e., bottom stage in vertical split), // do not create an input layer if (position.y >= SystemBarUtils.getStatusBarHeight(context)) return - if (!isCaptionVisible && statusBarInputLayerExists) { + if (!isCaptionVisible) { disposeStatusBarInputLayer() return } @@ -227,6 +227,7 @@ internal class AppHandleViewHolder( * is not visible. */ fun disposeStatusBarInputLayer() { + if (!statusBarInputLayerExists) return statusBarInputLayerExists = false handler.post { statusBarInputLayer?.releaseView() diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontLandscape.kt new file mode 100644 index 000000000000..898964f0fdbc --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontLandscape.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.wm.shell.flicker + +import android.tools.Rotation.ROTATION_90 +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner +import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.BRING_APPS_TO_FRONT +import com.android.wm.shell.scenarios.BringDesktopAppsToFront +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Bring apps to front by clicking on the App Header. + * + * Assert that the app windows move to front. + */ +@RunWith(FlickerServiceJUnit4ClassRunner::class) +class BringDesktopAppsToFrontLandscape : BringDesktopAppsToFront(rotation = ROTATION_90) { + + @ExpectedScenarios(["BRING_APPS_TO_FRONT"]) + @Test + override fun bringDesktopAppsToFront() = super.bringDesktopAppsToFront() + + companion object { + @JvmStatic + @FlickerConfigProvider + fun flickerConfigProvider(): FlickerConfig = + FlickerConfig() + .use(FlickerServiceConfig.DEFAULT) + .use(BRING_APPS_TO_FRONT) + } +} diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontPortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontPortrait.kt new file mode 100644 index 000000000000..b123d7d96129 --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/BringDesktopAppsToFrontPortrait.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.wm.shell.flicker + +import android.tools.Rotation.ROTATION_0 +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner +import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.BRING_APPS_TO_FRONT +import com.android.wm.shell.scenarios.BringDesktopAppsToFront +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Bring apps to front by clicking on the App Header. + * + * Assert that the app windows move to front. + */ +@RunWith(FlickerServiceJUnit4ClassRunner::class) +class BringDesktopAppsToFrontPortrait : BringDesktopAppsToFront(rotation = ROTATION_0) { + + @ExpectedScenarios(["BRING_APPS_TO_FRONT"]) + @Test + override fun bringDesktopAppsToFront() = super.bringDesktopAppsToFront() + + companion object { + @JvmStatic + @FlickerConfigProvider + fun flickerConfigProvider(): FlickerConfig = + FlickerConfig() + .use(FlickerServiceConfig.DEFAULT) + .use(BRING_APPS_TO_FRONT) + } +} diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt index 4cddf31321d6..88dc5489b404 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt @@ -25,6 +25,7 @@ import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAlways import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAtStart import android.tools.flicker.assertors.assertions.AppWindowAlignsWithOnlyOneDisplayCornerAtEnd import android.tools.flicker.assertors.assertions.AppWindowBecomesInvisible +import android.tools.flicker.assertors.assertions.AppWindowBecomesTopWindow import android.tools.flicker.assertors.assertions.AppWindowBecomesVisible import android.tools.flicker.assertors.assertions.AppWindowCoversLeftHalfScreenAtEnd import android.tools.flicker.assertors.assertions.AppWindowCoversRightHalfScreenAtEnd @@ -345,6 +346,30 @@ class DesktopModeFlickerScenarios { ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }), ) + val BRING_APPS_TO_FRONT = + FlickerConfigEntry( + scenarioId = ScenarioId("BRING_APPS_TO_FRONT"), + extractor = + ShellTransitionScenarioExtractor( + transitionMatcher = + object : ITransitionMatcher { + override fun findAll( + transitions: Collection<Transition> + ): Collection<Transition> { + return transitions.filter { + it.type == TransitionType.TO_FRONT + } + } + } + ), + assertions = + AssertionTemplates.COMMON_ASSERTIONS + + listOf( + AppWindowBecomesTopWindow(DESKTOP_MODE_APP), + AppWindowOnTopAtEnd(DESKTOP_MODE_APP), + ).associateBy({ it }, { AssertionInvocationGroup.BLOCKING }) + ) + val CASCADE_APP = FlickerConfigEntry( scenarioId = ScenarioId("CASCADE_APP"), diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZoneLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZoneLandscape.kt new file mode 100644 index 000000000000..e1120bdda194 --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZoneLandscape.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.wm.shell.flicker + +import android.tools.Rotation.ROTATION_90 +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner +import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP +import com.android.wm.shell.scenarios.MaximizeAppWindowWithDragToTopDragZone +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Maximize app window by dragging it to the top drag zone. + * + * Assert that the app window keeps the same increases in size, filling the vertical and horizontal + * stable display bounds. + */ +@RunWith(FlickerServiceJUnit4ClassRunner::class) +class MaximizeAppWindowWithDragToTopDragZoneLandscape : MaximizeAppWindowWithDragToTopDragZone( + rotation = ROTATION_90 +) { + @ExpectedScenarios(["MAXIMIZE_APP"]) + @Test + override fun maximizeAppWithDragToTopDragZone() = super.maximizeAppWithDragToTopDragZone() + + companion object { + @JvmStatic + @FlickerConfigProvider + fun flickerConfigProvider(): FlickerConfig = + FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MAXIMIZE_APP) + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZonePortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZonePortrait.kt new file mode 100644 index 000000000000..fb910c7b907d --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWindowWithDragToTopDragZonePortrait.kt @@ -0,0 +1,48 @@ +/* + * 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.flicker + +import android.tools.flicker.FlickerConfig +import android.tools.flicker.annotation.ExpectedScenarios +import android.tools.flicker.annotation.FlickerConfigProvider +import android.tools.flicker.config.FlickerConfig +import android.tools.flicker.config.FlickerServiceConfig +import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner +import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP +import com.android.wm.shell.scenarios.MaximizeAppWindowWithDragToTopDragZone +import org.junit.Test +import org.junit.runner.RunWith + +/** + * Maximize app window by dragging it to the top drag zone. + * + * Assert that the app window keeps the same increases in size, filling the vertical and horizontal + * stable display bounds. + */ +@RunWith(FlickerServiceJUnit4ClassRunner::class) +class MaximizeAppWindowWithDragToTopDragZonePortrait : MaximizeAppWindowWithDragToTopDragZone() { + @ExpectedScenarios(["MAXIMIZE_APP"]) + @Test + override fun maximizeAppWithDragToTopDragZone() = super.maximizeAppWithDragToTopDragZone() + + companion object { + @JvmStatic + @FlickerConfigProvider + fun flickerConfigProvider(): FlickerConfig = + FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MAXIMIZE_APP) + } +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.kt new file mode 100644 index 000000000000..6c8cc68da7c0 --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/BringDesktopAppsToFrontTest.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.wm.shell.functional + +import android.platform.test.annotations.Postsubmit +import com.android.wm.shell.scenarios.BringDesktopAppsToFront +import org.junit.runner.RunWith +import org.junit.runners.BlockJUnit4ClassRunner + +/** Functional test for [BringDesktopAppsToFront]. */ +@RunWith(BlockJUnit4ClassRunner::class) +@Postsubmit +class BringDesktopAppsToFrontTest : BringDesktopAppsToFront() diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/BringDesktopAppsToFront.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/BringDesktopAppsToFront.kt new file mode 100644 index 000000000000..1db22ebb8c73 --- /dev/null +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/BringDesktopAppsToFront.kt @@ -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.wm.shell.scenarios + +import android.tools.NavBar +import android.tools.Rotation +import android.tools.flicker.rules.ChangeDisplayOrientationRule +import com.android.server.wm.flicker.helpers.DesktopModeAppHelper +import com.android.server.wm.flicker.helpers.MailAppHelper +import com.android.window.flags.Flags +import com.android.wm.shell.Utils +import org.junit.After +import org.junit.Assume +import org.junit.Before +import org.junit.Ignore +import org.junit.Rule +import org.junit.Test + +@Ignore("Test Base Class") +abstract class BringDesktopAppsToFront( + val rotation: Rotation = Rotation.ROTATION_0, + isResizable: Boolean = true, + isLandscapeApp: Boolean = true, +) : DesktopScenarioCustomAppTestBase(isResizable, isLandscapeApp) { + + private val mailApp = DesktopModeAppHelper(MailAppHelper(instrumentation)) + + @Rule + @JvmField val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, rotation) + + @Before + fun setup() { + Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) + tapl.setEnableRotation(true) + tapl.setExpectedRotation(rotation.value) + ChangeDisplayOrientationRule.setRotation(rotation) + tapl.enableTransientTaskbar(false) + // Launch a first app and snap it to left side so that it doesn't overlap too much with + // the next launching app, and their headers are visible enough to switch focus by tapping + // on them. + testApp.enterDesktopMode(wmHelper, device) + testApp.snapResizeDesktopApp(wmHelper, device, instrumentation.context, toLeft = true) + mailApp.launchViaIntent(wmHelper) + } + + @Test + open fun bringDesktopAppsToFront() { + testApp.bringToFront(wmHelper, device) + mailApp.bringToFront(wmHelper, device) + testApp.bringToFront(wmHelper, device) + mailApp.bringToFront(wmHelper, device) + } + + @After + fun teardown() { + mailApp.exit(wmHelper) + testApp.exit(wmHelper) + } +} diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt index 351a70094654..f9bf49ecae1c 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/CloseAllAppsWithAppHeaderExit.kt @@ -57,7 +57,7 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0) { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) tapl.setEnableRotation(true) tapl.setExpectedRotation(rotation.value) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) mailApp.launchViaIntent(wmHelper) nonResizeableApp.launchViaIntent(wmHelper) } diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt index 3f9927f1fab6..16e537361b66 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindow.kt @@ -40,7 +40,7 @@ abstract class DragAppWindowMultiWindow : DragAppWindowScenarioTestBase() @Before fun setup() { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) mailApp.launchViaIntent(wmHelper) newTasksApp.launchViaIntent(wmHelper) imeApp.launchViaIntent(wmHelper) diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt index 6d52a11153d9..c43a57594fb3 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowMultiWindowAndPip.kt @@ -47,7 +47,7 @@ open class DragAppWindowMultiWindowAndPip : DragAppWindowScenarioTestBase() Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) // Set string extra to ensure the app is on PiP mode at launch pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = mapOf("enter_pip" to "true")) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) mailApp.launchViaIntent(wmHelper) newTasksApp.launchViaIntent(wmHelper) imeApp.launchViaIntent(wmHelper) diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt index 91cfd17340fc..786a8b710434 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/DragAppWindowSingleWindow.kt @@ -36,7 +36,7 @@ open class DragAppWindowSingleWindow : DragAppWindowScenarioTestBase() @Before fun setup() { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt index 967bd29958c2..0f546cdf97c5 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopWithDrag.kt @@ -49,7 +49,7 @@ constructor( @Test open fun enterDesktopWithDrag() { - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopModeWithDrag(wmHelper, device) } @After diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt index f442fdb31592..28008393da84 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopWithDragToTopDragZone.kt @@ -46,7 +46,7 @@ constructor( instrumentation.context.resources.getBoolean(R.bool.config_dragToMaximizeInDesktopMode)) tapl.setEnableRotation(true) tapl.setExpectedRotation(rotation.value) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt index 6637b01f9d9c..5cf51e3be18c 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximiseAppWithCornerResize.kt @@ -66,7 +66,7 @@ abstract class MaximiseAppWithCornerResize( tapl.setEnableRotation(true) tapl.setExpectedRotation(rotation.value) ChangeDisplayOrientationRule.setRotation(rotation) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) testApp.cornerResize( wmHelper, device, diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt index a54d497bf511..d2be4944d365 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt @@ -58,7 +58,7 @@ constructor(private val rotation: Rotation = Rotation.ROTATION_0, isResizable: B tapl.setEnableRotation(true) tapl.setExpectedRotation(rotation.value) ChangeDisplayOrientationRule.setRotation(rotation) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt index a2b88f278ff2..60a0fb547909 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindowWithDragToTopDragZone.kt @@ -59,7 +59,7 @@ constructor(private val rotation: Rotation = Rotation.ROTATION_0) { tapl.setEnableRotation(true) tapl.setExpectedRotation(rotation.value) ChangeDisplayOrientationRule.setRotation(rotation) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt index b5483634b057..971637b62604 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeAppWindows.kt @@ -61,7 +61,7 @@ constructor(private val rotation: Rotation = Rotation.ROTATION_0) { tapl.setEnableRotation(true) tapl.setExpectedRotation(rotation.value) ChangeDisplayOrientationRule.setRotation(rotation) - testApp1.enterDesktopWithDrag(wmHelper, device) + testApp1.enterDesktopMode(wmHelper, device) testApp2.launchViaIntent(wmHelper) testApp3.launchViaIntent(wmHelper) } diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt index b86765e23422..7987f7ec59fa 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MinimizeWindowOnAppOpen.kt @@ -58,7 +58,7 @@ open class MinimizeWindowOnAppOpen() @Before fun setup() { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) mailApp.launchViaIntent(wmHelper) newTasksApp.launchViaIntent(wmHelper) imeApp.launchViaIntent(wmHelper) diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt index aad266fb8374..6ce36f53f0d1 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/OpenAppsInDesktopMode.kt @@ -61,7 +61,7 @@ abstract class OpenAppsInDesktopMode(val rotation: Rotation = Rotation.ROTATION_ tapl.setExpectedRotation(rotation.value) tapl.enableTransientTaskbar(false) ChangeDisplayOrientationRule.setRotation(rotation) - firstApp.enterDesktopWithDrag(wmHelper, device) + firstApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt index bfee3181cbc0..eefa0bb3c00a 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindow.kt @@ -61,7 +61,7 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0, Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) tapl.setEnableRotation(true) tapl.setExpectedRotation(rotation.value) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) mailApp.launchViaIntent(wmHelper) newTasksApp.launchViaIntent(wmHelper) imeApp.launchViaIntent(wmHelper) diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt index 5b1b64e7c562..0226eb35de14 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppCornerMultiWindowAndPip.kt @@ -65,7 +65,7 @@ constructor(val rotation: Rotation = Rotation.ROTATION_0, tapl.setExpectedRotation(rotation.value) // Set string extra to ensure the app is on PiP mode at launch pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = mapOf("enter_pip" to "true")) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) mailApp.launchViaIntent(wmHelper) newTasksApp.launchViaIntent(wmHelper) imeApp.launchViaIntent(wmHelper) diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt index a7cebf402d8e..64636230e5e0 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithCornerResize.kt @@ -67,7 +67,7 @@ abstract class ResizeAppWithCornerResize( tapl.setEnableRotation(true) ChangeDisplayOrientationRule.setRotation(rotation) tapl.setExpectedRotation(rotation.value) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt index 67802387b267..f198cfed7c50 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ResizeAppWithEdgeResize.kt @@ -60,7 +60,7 @@ constructor( ) tapl.setEnableRotation(true) tapl.setExpectedRotation(rotation.value) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt index 2b40497844ef..fd4c2434589d 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithButton.kt @@ -56,7 +56,7 @@ constructor(private val toLeft: Boolean = true, isResizable: Boolean = true) { @Before fun setup() { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt index b4bd7e1c5211..62e860ed24a7 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SnapResizeAppWindowWithDrag.kt @@ -56,7 +56,7 @@ constructor(private val toLeft: Boolean = true, isResizable: Boolean = true) { @Before fun setup() { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt index f08e50e0d4ee..de330e072ad1 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionResizeAndDrag.kt @@ -59,7 +59,7 @@ open class StartAppMediaProjectionResizeAndDrag { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) tapl.setEnableRotation(true) tapl.setExpectedRotation(0) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt index ce235d445fe5..4b3f15f1db86 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartAppMediaProjectionWithMaxDesktopWindows.kt @@ -67,7 +67,7 @@ open class StartAppMediaProjectionWithMaxDesktopWindows { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) tapl.setEnableRotation(true) tapl.setExpectedRotation(0) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt index 005195296c62..a1083671f687 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/StartScreenMediaProjectionWithMaxDesktopWindows.kt @@ -62,7 +62,7 @@ open class StartScreenMediaProjectionWithMaxDesktopWindows { @Before fun setup() { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt index dad2eb633c72..1455bd1888e2 100644 --- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt +++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/SwitchToOverviewFromDesktop.kt @@ -54,7 +54,7 @@ constructor(val navigationMode: NavBar = NavBar.MODE_GESTURAL) { @Before fun setup() { Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet) - testApp.enterDesktopWithDrag(wmHelper, device) + testApp.enterDesktopMode(wmHelper, device) } @Test diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt index a248303b1c33..fd4328dee0a1 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt @@ -16,16 +16,18 @@ package com.android.wm.shell.flicker.pip +import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresDevice +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.subject.exceptions.ExceptionMessageBuilder import android.tools.flicker.subject.exceptions.IncorrectRegionException import android.tools.flicker.subject.layers.LayerSubject -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.Assume import org.junit.FixMethodOrder @@ -35,6 +37,7 @@ import org.junit.runners.MethodSorters import org.junit.runners.Parameterized import kotlin.math.abs + /** * Test entering pip from an app via auto-enter property when navigating to home. * @@ -60,6 +63,7 @@ import kotlin.math.abs @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt index df952c925720..d4ad4ef8a401 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipWithSourceRectHintTest.kt @@ -17,10 +17,12 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.traces.component.ComponentNameMatcher +import com.android.wm.shell.Flags import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith @@ -52,6 +54,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class AutoEnterPipWithSourceRectHintTest(flicker: LegacyFlickerTest) : AutoEnterPipOnGoToHomeTest(flicker) { override val defaultEnterPip: FlickerBuilder.() -> Unit = { diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt index 302b8c414979..cc6e4b5a90d5 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipBySwipingDownTest.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest @@ -53,6 +54,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class ClosePipBySwipingDownTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt index 77a1edb7039a..53725fa046c6 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ClosePipWithDismissButtonTest.kt @@ -17,9 +17,11 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.ClosePipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -52,6 +54,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class ClosePipWithDismissButtonTest(flicker: LegacyFlickerTest) : ClosePipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { pipApp.closePipWindow(wmHelper) } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt index 6e32d6412b50..a1551b7924fe 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt @@ -17,9 +17,11 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.Assume import org.junit.FixMethodOrder @@ -43,6 +45,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { tapl.goHome() } } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt index 9a6cb61cfc66..ea5b3e5b08df 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientation.kt @@ -19,6 +19,7 @@ package com.android.wm.shell.flicker.pip import android.app.Activity import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.Rotation import android.tools.flicker.assertions.FlickerTest import android.tools.flicker.junit.FlickerParametersRunnerFactory @@ -32,6 +33,7 @@ import com.android.server.wm.flicker.entireScreenCovered import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT @@ -68,6 +70,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class EnterPipToOtherOrientation(flicker: LegacyFlickerTest) : PipTransition(flicker) { private val testApp = FixedOrientationAppHelper(instrumentation) private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt index 6b4751cee3bb..a109c4bba2b3 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipViaAppUiButtonTest.kt @@ -16,9 +16,11 @@ package com.android.wm.shell.flicker.pip +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.EnterPipTransition import org.junit.FixMethodOrder import org.junit.runner.RunWith @@ -49,6 +51,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) open class EnterPipViaAppUiButtonTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { pipApp.clickEnterPipButton(wmHelper) } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt index 8d0bc0f5a155..14ec303206ee 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaExpandButtonTest.kt @@ -16,9 +16,11 @@ package com.android.wm.shell.flicker.pip +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition import org.junit.FixMethodOrder import org.junit.runner.RunWith @@ -51,6 +53,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class ExitPipToAppViaExpandButtonTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt index 939f3280d2e6..8a34b5e27fdb 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExitPipToAppViaIntentTest.kt @@ -16,9 +16,11 @@ package com.android.wm.shell.flicker.pip +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.ExitPipToAppTransition import org.junit.FixMethodOrder import org.junit.runner.RunWith @@ -50,6 +52,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class ExitPipToAppViaIntentTest(flicker: LegacyFlickerTest) : ExitPipToAppTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { setup { diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt index 258663b5556d..4f189fc6190d 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt @@ -17,12 +17,14 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.Rotation import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.traces.component.ComponentNameMatcher +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -54,6 +56,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class ExpandPipOnDoubleClickTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { pipApp.doubleClickPipWindow(wmHelper) } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt index 1964e3cebc89..4d72b03d0345 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt @@ -17,11 +17,13 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.Rotation import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -33,6 +35,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class ExpandPipOnPinchOpenTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { pipApp.pinchOpenPipWindow(wmHelper, 0.25f, 30) } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt index 5f8ac2af241b..1c40d89aec80 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenAutoEnterPipOnGoToHomeTest.kt @@ -16,7 +16,10 @@ package com.android.wm.shell.flicker.pip +import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresDevice +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.Rotation import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder @@ -24,10 +27,9 @@ import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.helpers.WindowUtils import android.tools.traces.parsers.toFlickerComponent -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.Assume import org.junit.FixMethodOrder @@ -62,6 +64,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class FromSplitScreenAutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : AutoEnterPipOnGoToHomeTest(flicker) { private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt index 48c85a84e556..12e23285ea68 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/FromSplitScreenEnterPipOnUserLeaveHintTest.kt @@ -16,7 +16,10 @@ package com.android.wm.shell.flicker.pip +import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresDevice +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.Rotation import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder @@ -24,10 +27,9 @@ import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.helpers.WindowUtils import android.tools.traces.parsers.toFlickerComponent -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.EnterPipTransition import com.android.wm.shell.flicker.utils.SplitScreenUtils import org.junit.Assume @@ -63,6 +65,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class FromSplitScreenEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransition(flicker) { private val portraitDisplayBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt index ee62cf59b2f9..d979b428d8b2 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipDownOnShelfHeightChange.kt @@ -17,10 +17,12 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresDevice +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest -import androidx.test.filters.RequiresDevice +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition import com.android.wm.shell.flicker.utils.Direction import org.junit.FixMethodOrder @@ -56,6 +58,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class MovePipDownOnShelfHeightChange(flicker: LegacyFlickerTest) : MovePipShelfHeightTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt index 04fedf4f2550..88d78edae94a 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipOnImeVisibilityChangeTest.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.Rotation import android.tools.flicker.assertions.FlickerTest import android.tools.flicker.junit.FlickerParametersRunnerFactory @@ -27,6 +28,7 @@ import android.tools.helpers.WindowUtils import android.tools.traces.component.ComponentNameMatcher import com.android.server.wm.flicker.helpers.ImeAppHelper import com.android.server.wm.flicker.helpers.setRotation +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -41,6 +43,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class MovePipOnImeVisibilityChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { private val imeApp = ImeAppHelper(instrumentation) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt index 4d643f7b4408..c533800b37c5 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/MovePipUpOnShelfHeightChangeTest.kt @@ -17,10 +17,12 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresDevice +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest -import androidx.test.filters.RequiresDevice +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.MovePipShelfHeightTransition import com.android.wm.shell.flicker.utils.Direction import org.junit.FixMethodOrder @@ -56,6 +58,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) open class MovePipUpOnShelfHeightChangeTest(flicker: LegacyFlickerTest) : MovePipShelfHeightTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { @@ -65,7 +68,8 @@ open class MovePipUpOnShelfHeightChangeTest(flicker: LegacyFlickerTest) : } /** Checks that the visible region of [pipApp] window always moves up during the animation. */ - @Presubmit @Test fun pipWindowMovesUp() = pipWindowMoves(Direction.UP) + @Presubmit + @Test fun pipWindowMovesUp() = pipWindowMoves(Direction.UP) /** Checks that the visible region of [pipApp] layer always moves up during the animation. */ @Presubmit @Test fun pipLayerMovesUp() = pipLayerMoves(Direction.UP) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt index 429774f890a5..04016a93e53d 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipAspectRatioChangeTest.kt @@ -17,11 +17,13 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.Rotation import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -33,6 +35,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class PipAspectRatioChangeTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { pipApp.changeAspectRatio(wmHelper) } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt index a4df69fc6539..6bcaabc3b680 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragTest.kt @@ -18,11 +18,13 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit import android.platform.test.annotations.RequiresDevice +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -35,6 +37,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class PipDragTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { private var isDraggedLeft: Boolean = true diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt index cbd4a528474a..d82bfdd6dc2f 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipDragThenSnapTest.kt @@ -17,16 +17,18 @@ package com.android.wm.shell.flicker.pip import android.graphics.Rect +import android.platform.test.annotations.FlakyTest +import android.platform.test.annotations.RequiresDevice +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.Rotation import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.flicker.rules.RemoveAllTasksButHomeRule -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.testapp.ActivityOptions +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -40,6 +42,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class PipDragThenSnapTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { // represents the direction in which the pip window should be snapping private var willSnapRight: Boolean = true diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt index 16d08e5e9055..dbc97d072f9b 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/PipPinchInTest.kt @@ -17,13 +17,15 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresDevice +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.Rotation import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.flicker.subject.exceptions.IncorrectRegionException -import androidx.test.filters.RequiresDevice +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -36,6 +38,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class PipPinchInTest(flicker: LegacyFlickerTest) : PipTransition(flicker) { override val thisTransition: FlickerBuilder.() -> Unit = { transitions { pipApp.pinchInPipWindow(wmHelper, 0.4f, 30) } diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt index 578a9b536289..9d46ac1d6e00 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinned.kt @@ -17,8 +17,11 @@ package com.android.wm.shell.flicker.pip import android.app.Activity +import android.platform.test.annotations.FlakyTest import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresDevice +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.Rotation import android.tools.flicker.assertions.FlickerTest import android.tools.flicker.junit.FlickerParametersRunnerFactory @@ -26,10 +29,9 @@ import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.helpers.WindowUtils -import androidx.test.filters.FlakyTest -import androidx.test.filters.RequiresDevice import com.android.server.wm.flicker.testapp.ActivityOptions import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import com.android.wm.shell.flicker.pip.common.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE import org.junit.Assume @@ -48,6 +50,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) open class SetRequestedOrientationWhilePinned(flicker: LegacyFlickerTest) : PipTransition(flicker) { private val startingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_0) private val endingBounds = WindowUtils.getDisplayBounds(Rotation.ROTATION_90) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt index c6cf3411835c..e72251fb7a31 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/ShowPipAndRotateDisplay.kt @@ -17,6 +17,7 @@ package com.android.wm.shell.flicker.pip import android.platform.test.annotations.Presubmit +import android.platform.test.annotations.RequiresFlagsDisabled import android.tools.flicker.assertions.FlickerTest import android.tools.flicker.junit.FlickerParametersRunnerFactory import android.tools.flicker.legacy.FlickerBuilder @@ -25,6 +26,7 @@ import android.tools.flicker.legacy.LegacyFlickerTestFactory import android.tools.helpers.WindowUtils import com.android.server.wm.flicker.helpers.SimpleAppHelper import com.android.server.wm.flicker.helpers.setRotation +import com.android.wm.shell.Flags import com.android.wm.shell.flicker.pip.common.PipTransition import org.junit.FixMethodOrder import org.junit.Test @@ -58,6 +60,7 @@ import org.junit.runners.Parameterized @RunWith(Parameterized::class) @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class) @FixMethodOrder(MethodSorters.NAME_ASCENDING) +@RequiresFlagsDisabled(Flags.FLAG_ENABLE_PIP2) class ShowPipAndRotateDisplay(flicker: LegacyFlickerTest) : PipTransition(flicker) { private val testApp = SimpleAppHelper(instrumentation) private val screenBoundsStart = WindowUtils.getDisplayBounds(flicker.scenario.startRotation) diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt index bc2bfdbe1df1..c37bf3579e93 100644 --- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt +++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipTransition.kt @@ -20,6 +20,7 @@ import android.app.Instrumentation import android.content.Intent import android.platform.test.annotations.Postsubmit import android.platform.test.annotations.Presubmit +import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.tools.Rotation import android.tools.flicker.legacy.FlickerBuilder import android.tools.flicker.legacy.LegacyFlickerTest @@ -31,9 +32,14 @@ import com.android.server.wm.flicker.helpers.setRotation import com.android.server.wm.flicker.testapp.ActivityOptions import com.android.wm.shell.flicker.BaseTest import com.google.common.truth.Truth +import org.junit.Rule import org.junit.Test abstract class PipTransition(flicker: LegacyFlickerTest) : BaseTest(flicker) { + @JvmField + @Rule + val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule() + protected val pipApp = PipAppHelper(instrumentation) protected val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation) protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestSyncExecutor.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestSyncExecutor.kt new file mode 100644 index 000000000000..528ca7e94ee3 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/TestSyncExecutor.kt @@ -0,0 +1,38 @@ +/* + * 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 + +import com.android.wm.shell.common.ShellExecutor + +/** + * Test ShellExecutor that runs everything synchronously. + */ +class TestSyncExecutor : ShellExecutor { + override fun execute(runnable: Runnable) { + runnable.run() + } + + override fun executeDelayed(runnable: Runnable, delayMillis: Long) { + runnable.run() + } + + override fun removeCallbacks(runnable: Runnable) { + } + + override fun hasCallback(runnable: Runnable): Boolean { + return false + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxConfigurationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxConfigurationTest.kt new file mode 100644 index 000000000000..75025d9064d3 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxConfigurationTest.kt @@ -0,0 +1,160 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui.letterbox + +import android.annotation.ColorRes +import android.content.Context +import android.content.res.Resources +import android.graphics.Color +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn +import com.android.internal.R +import com.android.wm.shell.ShellTestCase +import java.util.function.Consumer +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn + +/** + * Tests for [LetterboxConfiguration]. + * + * Build/Install/Run: + * atest WMShellUnitTests:LetterboxConfigurationTest + */ +@RunWith(AndroidTestingRunner::class) +@SmallTest +class LetterboxConfigurationTest : ShellTestCase() { + + companion object { + @JvmStatic + val COLOR_WHITE = Color.valueOf(Color.WHITE) + @JvmStatic + val COLOR_RED = Color.valueOf(Color.RED) + @JvmStatic + val COLOR_BLACK = Color.valueOf(Color.BLACK) + @JvmStatic + val COLOR_WHITE_RESOURCE_ID = android.R.color.white + @JvmStatic + val COLOR_BLACK_RESOURCE_ID = android.R.color.black + } + + @Test + fun `default background color is used if override is not set`() { + runTestScenario { r -> + r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID) + r.loadConfiguration() + r.checkBackgroundColor(COLOR_WHITE) + } + } + + @Test + fun `overridden background color is used if set`() { + runTestScenario { r -> + r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID) + r.loadConfiguration() + r.overrideBackgroundColor(COLOR_RED) + r.checkBackgroundColor(COLOR_RED) + } + } + + @Test + fun `overridden background color resource is used if set without override`() { + runTestScenario { r -> + r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID) + r.loadConfiguration() + r.overrideBackgroundColorId(COLOR_BLACK_RESOURCE_ID) + r.checkBackgroundColor(COLOR_BLACK) + } + } + + @Test + fun `overridden background color has precedence over color id`() { + runTestScenario { r -> + r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID) + r.loadConfiguration() + r.overrideBackgroundColor(COLOR_RED) + r.overrideBackgroundColorId(COLOR_BLACK_RESOURCE_ID) + r.checkBackgroundColor(COLOR_RED) + } + } + + @Test + fun `reset background color`() { + runTestScenario { r -> + r.setDefaultBackgroundColorId(COLOR_WHITE_RESOURCE_ID) + r.loadConfiguration() + r.overrideBackgroundColor(COLOR_RED) + r.checkBackgroundColor(COLOR_RED) + + r.resetBackgroundColor() + r.checkBackgroundColor(COLOR_WHITE) + + r.overrideBackgroundColorId(COLOR_BLACK_RESOURCE_ID) + r.checkBackgroundColor(COLOR_BLACK) + + r.resetBackgroundColor() + r.checkBackgroundColor(COLOR_WHITE) + } + } + + /** + * Runs a test scenario providing a Robot. + */ + fun runTestScenario(consumer: Consumer<LetterboxConfigurationRobotTest>) { + val robot = LetterboxConfigurationRobotTest(mContext) + consumer.accept(robot) + } + + class LetterboxConfigurationRobotTest(private val ctx: Context) { + + private val resources: Resources + private lateinit var letterboxConfig: LetterboxConfiguration + + init { + resources = ctx.resources + spyOn(resources) + } + + fun setDefaultBackgroundColorId(@ColorRes colorId: Int) { + doReturn(colorId).`when`(resources) + .getColor(R.color.config_letterboxBackgroundColor, null) + } + + fun loadConfiguration() { + letterboxConfig = LetterboxConfiguration(ctx) + } + + fun overrideBackgroundColor(color: Color) { + letterboxConfig.setLetterboxBackgroundColor(color) + } + + fun resetBackgroundColor() { + letterboxConfig.resetLetterboxBackgroundColor() + } + + fun overrideBackgroundColorId(@ColorRes colorId: Int) { + letterboxConfig.setLetterboxBackgroundColorResourceId(colorId) + } + + fun checkBackgroundColor(expected: Color) { + val colorComponents = letterboxConfig.getBackgroundColorRgbArray() + val expectedComponents = expected.components + assert(expectedComponents.contentEquals(colorComponents)) + } + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt new file mode 100644 index 000000000000..1ae1c3fc4563 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxTransitionObserverTest.kt @@ -0,0 +1,294 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.compatui.letterbox + +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule +import android.testing.AndroidTestingRunner +import android.view.WindowManager.TRANSIT_CLOSE +import androidx.test.filters.SmallTest +import com.android.window.flags.Flags +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.transition.Transitions +import com.android.wm.shell.util.TransitionObserverInputBuilder +import com.android.wm.shell.util.executeTransitionObserverTest +import java.util.function.Consumer +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito +import org.mockito.kotlin.any +import org.mockito.kotlin.eq +import org.mockito.kotlin.never +import org.mockito.kotlin.times +import org.mockito.kotlin.anyOrNull +import org.mockito.verification.VerificationMode + +/** + * Tests for [LetterboxTransitionObserver]. + * + * Build/Install/Run: + * atest WMShellUnitTests:LetterboxTransitionObserverTest + */ +@RunWith(AndroidTestingRunner::class) +@SmallTest +class LetterboxTransitionObserverTest : ShellTestCase() { + + @get:Rule + val setFlagsRule: SetFlagsRule = SetFlagsRule() + + @Test + @DisableFlags(Flags.FLAG_APP_COMPAT_REFACTORING) + fun `when initialized and flag disabled the observer is not registered`() { + runTestScenario { r -> + executeTransitionObserverTest(observerFactory = r.observerFactory) { + r.invokeShellInit() + r.checkObservableIsRegistered(expected = false) + } + } + } + + @Test + @EnableFlags(Flags.FLAG_APP_COMPAT_REFACTORING) + fun `when initialized and flag enabled the observer is registered`() { + runTestScenario { r -> + executeTransitionObserverTest(observerFactory = r.observerFactory) { + r.invokeShellInit() + r.checkObservableIsRegistered(expected = true) + } + } + } + + @Test + fun `LetterboxController not used without TaskInfos in Change`() { + runTestScenario { r -> + executeTransitionObserverTest(observerFactory = r.observerFactory) { + r.invokeShellInit() + + inputBuilder { + buildTransitionInfo() + addChange(createChange()) + addChange(createChange()) + addChange(createChange()) + } + + validateOutput { + r.creationEventDetected(expected = false) + r.visibilityEventDetected(expected = false) + r.destroyEventDetected(expected = false) + r.boundsEventDetected(expected = false) + } + } + } + } + + @Test + fun `When a topActivity is letterboxed surfaces creation is requested`() { + runTestScenario { r -> + executeTransitionObserverTest(observerFactory = r.observerFactory) { + r.invokeShellInit() + + inputBuilder { + buildTransitionInfo() + r.createTopActivityChange(inputBuilder = this, isLetterboxed = true) + } + + validateOutput { + r.creationEventDetected(expected = true) + r.visibilityEventDetected(expected = true, visible = true) + r.destroyEventDetected(expected = false) + r.boundsEventDetected(expected = true) + } + } + } + } + + @Test + fun `When a topActivity is not letterboxed visibility is updated`() { + runTestScenario { r -> + executeTransitionObserverTest(observerFactory = r.observerFactory) { + r.invokeShellInit() + + inputBuilder { + buildTransitionInfo() + r.createTopActivityChange(inputBuilder = this, isLetterboxed = false) + } + + validateOutput { + r.creationEventDetected(expected = false) + r.visibilityEventDetected(expected = true, visible = false) + r.destroyEventDetected(expected = false) + r.boundsEventDetected(expected = false) + } + } + } + } + + @Test + fun `When closing change letterbox surface destroy is triggered`() { + runTestScenario { r -> + executeTransitionObserverTest(observerFactory = r.observerFactory) { + r.invokeShellInit() + + inputBuilder { + buildTransitionInfo() + r.createClosingChange(inputBuilder = this) + } + + validateOutput { + r.destroyEventDetected(expected = true) + r.creationEventDetected(expected = false) + r.visibilityEventDetected(expected = false, visible = false) + r.boundsEventDetected(expected = false) + } + } + } + } + + /** + * Runs a test scenario providing a Robot. + */ + fun runTestScenario(consumer: Consumer<LetterboxTransitionObserverRobotTest>) { + val robot = LetterboxTransitionObserverRobotTest() + consumer.accept(robot) + } + + class LetterboxTransitionObserverRobotTest { + + companion object { + @JvmStatic + private val DISPLAY_ID = 1 + + @JvmStatic + private val TASK_ID = 20 + } + + private val executor: ShellExecutor + private val shellInit: ShellInit + private val transitions: Transitions + private val letterboxController: LetterboxController + private val letterboxObserver: LetterboxTransitionObserver + + val observerFactory: () -> LetterboxTransitionObserver + + init { + executor = Mockito.mock(ShellExecutor::class.java) + shellInit = ShellInit(executor) + transitions = Mockito.mock(Transitions::class.java) + letterboxController = Mockito.mock(LetterboxController::class.java) + letterboxObserver = + LetterboxTransitionObserver(shellInit, transitions, letterboxController) + observerFactory = { letterboxObserver } + } + + fun invokeShellInit() = shellInit.init() + + fun observer() = letterboxObserver + + fun checkObservableIsRegistered(expected: Boolean) { + Mockito.verify(transitions, expected.asMode()).registerObserver(observer()) + } + + fun creationEventDetected( + expected: Boolean, + displayId: Int = DISPLAY_ID, + taskId: Int = TASK_ID + ) { + Mockito.verify(letterboxController, expected.asMode()).createLetterboxSurface( + toLetterboxKeyMatcher(displayId, taskId), + anyOrNull(), + anyOrNull() + ) + } + + fun visibilityEventDetected( + expected: Boolean, + displayId: Int = DISPLAY_ID, + taskId: Int = TASK_ID, + visible: Boolean? = null + ) { + Mockito.verify(letterboxController, expected.asMode()).updateLetterboxSurfaceVisibility( + toLetterboxKeyMatcher(displayId, taskId), + anyOrNull(), + visible.asMatcher() + ) + } + + fun destroyEventDetected( + expected: Boolean, + displayId: Int = DISPLAY_ID, + taskId: Int = TASK_ID + ) { + Mockito.verify(letterboxController, expected.asMode()).destroyLetterboxSurface( + toLetterboxKeyMatcher(displayId, taskId), + anyOrNull() + ) + } + + fun boundsEventDetected( + expected: Boolean, + displayId: Int = DISPLAY_ID, + taskId: Int = TASK_ID + ) { + Mockito.verify(letterboxController, expected.asMode()).updateLetterboxSurfaceBounds( + toLetterboxKeyMatcher(displayId, taskId), + anyOrNull(), + anyOrNull() + ) + } + + fun createTopActivityChange( + inputBuilder: TransitionObserverInputBuilder, + isLetterboxed: Boolean = true, + displayId: Int = DISPLAY_ID, + taskId: Int = TASK_ID + ) { + inputBuilder.addChange(changeTaskInfo = inputBuilder.createTaskInfo().apply { + appCompatTaskInfo.isTopActivityLetterboxed = isLetterboxed + this.taskId = taskId + this.displayId = displayId + }) + } + + fun createClosingChange( + inputBuilder: TransitionObserverInputBuilder, + displayId: Int = DISPLAY_ID, + taskId: Int = TASK_ID + ) { + inputBuilder.addChange(changeTaskInfo = inputBuilder.createTaskInfo().apply { + this.taskId = taskId + this.displayId = displayId + }, changeMode = TRANSIT_CLOSE) + } + + private fun Boolean.asMode(): VerificationMode = if (this) times(1) else never() + + private fun Boolean?.asMatcher(): Boolean = + if (this != null) eq(this) else any() + + private fun toLetterboxKeyMatcher(displayId: Int, taskId: Int): LetterboxKey { + if (displayId < 0 || taskId < 0) { + return any() + } else { + return eq(LetterboxKey(displayId, taskId)) + } + } + } +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt index f21f26443748..62717a32d99f 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopMixedTransitionHandlerTest.kt @@ -31,6 +31,8 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import android.view.SurfaceControl import android.view.WindowManager +import android.view.WindowManager.TRANSIT_CHANGE +import android.view.WindowManager.TRANSIT_NONE import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_BACK import android.view.WindowManager.TransitionType @@ -47,6 +49,7 @@ import com.android.wm.shell.desktopmode.DesktopMixedTransitionHandler.PendingMix import com.android.wm.shell.freeform.FreeformTaskTransitionHandler import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.Transitions +import com.android.wm.shell.util.StubTransaction import com.google.common.truth.Truth.assertThat import org.junit.Assert.assertFalse import org.junit.Assert.assertNull @@ -491,6 +494,72 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { } @Test + @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) + fun startLaunchTransition_unknownLaunchingTask_animates() { + val wct = WindowContainerTransaction() + val task = createTask(WINDOWING_MODE_FREEFORM) + val transition = Binder() + whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull())) + .thenReturn(transition) + whenever(transitions.dispatchTransition(eq(transition), any(), any(), any(), any(), any())) + .thenReturn(mock()) + + mixedHandler.startLaunchTransition( + transitionType = TRANSIT_OPEN, + wct = wct, + taskId = null, + ) + + val started = mixedHandler.startAnimation( + transition, + createTransitionInfo( + TRANSIT_OPEN, + listOf(createChange(task, mode = TRANSIT_OPEN)) + ), + StubTransaction(), + StubTransaction(), + ) { } + + assertThat(started).isEqualTo(true) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP) + fun startLaunchTransition_unknownLaunchingTaskOverImmersive_animatesImmersiveChange() { + val wct = WindowContainerTransaction() + val immersiveTask = createTask(WINDOWING_MODE_FREEFORM) + val openingTask = createTask(WINDOWING_MODE_FREEFORM) + val transition = Binder() + whenever(transitions.startTransition(eq(TRANSIT_OPEN), eq(wct), anyOrNull())) + .thenReturn(transition) + whenever(transitions.dispatchTransition(eq(transition), any(), any(), any(), any(), any())) + .thenReturn(mock()) + + mixedHandler.startLaunchTransition( + transitionType = TRANSIT_OPEN, + wct = wct, + taskId = null, + exitingImmersiveTask = immersiveTask.taskId, + ) + + val immersiveChange = createChange(immersiveTask, mode = TRANSIT_CHANGE) + val openingChange = createChange(openingTask, mode = TRANSIT_OPEN) + val started = mixedHandler.startAnimation( + transition, + createTransitionInfo( + TRANSIT_OPEN, + listOf(immersiveChange, openingChange) + ), + StubTransaction(), + StubTransaction(), + ) { } + + assertThat(started).isEqualTo(true) + verify(desktopImmersiveController) + .animateResizeChange(eq(immersiveChange), any(), any(), any()) + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS) fun addPendingAndAnimateLaunchTransition_noMinimizeChange_doesNotReparentMinimizeChange() { val wct = WindowContainerTransaction() @@ -712,9 +781,13 @@ class DesktopMixedTransitionHandlerTest : ShellTestCase() { changes.forEach { change -> addChange(change) } } - private fun createChange(task: RunningTaskInfo): TransitionInfo.Change = + private fun createChange( + task: RunningTaskInfo, + @TransitionInfo.TransitionMode mode: Int = TRANSIT_NONE + ): TransitionInfo.Change = TransitionInfo.Change(task.token, SurfaceControl()).apply { taskInfo = task + setMode(mode) } private fun createTask(@WindowingMode windowingMode: Int): RunningTaskInfo = diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt new file mode 100644 index 000000000000..9e63a6d922b8 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeKeyGestureHandlerTest.kt @@ -0,0 +1,312 @@ +/* + * 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.desktopmode + +import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.content.pm.ActivityInfo +import android.graphics.Rect +import android.hardware.input.InputManager +import android.hardware.input.InputManager.KeyGestureEventHandler +import android.hardware.input.KeyGestureEvent +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule +import android.testing.AndroidTestingRunner +import android.view.Display.DEFAULT_DISPLAY +import android.view.KeyEvent +import android.window.DisplayAreaInfo +import androidx.test.filters.SmallTest +import com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER +import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE +import com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS +import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT +import com.android.wm.shell.MockToken +import com.android.wm.shell.RootTaskDisplayAreaOrganizer +import com.android.wm.shell.ShellTaskOrganizer +import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreeformTask +import com.android.wm.shell.transition.FocusTransitionObserver +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.eq +import org.mockito.kotlin.whenever +import com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer +import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn +import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession +import com.android.dx.mockito.inline.extended.StaticMockitoSession +import com.android.window.flags.Flags.FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS +import com.android.wm.shell.common.DisplayController +import com.android.wm.shell.common.DisplayLayout +import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger +import com.android.wm.shell.shared.desktopmode.DesktopModeStatus +import com.android.wm.shell.sysui.ShellInit +import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel +import java.util.Optional +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.setMain +import org.junit.After +import org.mockito.Mockito.anyInt +import org.mockito.Mockito.spy +import org.mockito.Mockito.verify +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.quality.Strictness + +/** + * Test class for [DesktopModeKeyGestureHandler] + * + * Usage: atest WMShellUnitTests:DesktopModeKeyGestureHandlerTest + */ +@SmallTest +@RunWith(AndroidTestingRunner::class) +@ExperimentalCoroutinesApi +@EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_MODE) +class DesktopModeKeyGestureHandlerTest : ShellTestCase() { + + @JvmField @Rule val setFlagsRule = SetFlagsRule() + + private val rootTaskDisplayAreaOrganizer = mock<RootTaskDisplayAreaOrganizer>() + private val shellTaskOrganizer = mock<ShellTaskOrganizer>() + private val focusTransitionObserver = mock<FocusTransitionObserver>() + private val testExecutor = mock<ShellExecutor>() + private val inputManager = mock<InputManager>() + private val displayController = mock<DisplayController>() + private val displayLayout = mock<DisplayLayout>() + private val desktopModeWindowDecorViewModel = mock<DesktopModeWindowDecorViewModel>() + private val desktopTasksController = mock<DesktopTasksController>() + + private lateinit var desktopModeKeyGestureHandler: DesktopModeKeyGestureHandler + private lateinit var keyGestureEventHandler: KeyGestureEventHandler + private lateinit var mockitoSession: StaticMockitoSession + private lateinit var testScope: CoroutineScope + private lateinit var shellInit: ShellInit + + // Mock running tasks are registered here so we can get the list from mock shell task organizer + private val runningTasks = mutableListOf<RunningTaskInfo>() + + @Before + fun setUp() { + Dispatchers.setMain(StandardTestDispatcher()) + mockitoSession = + mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(DesktopModeStatus::class.java) + .startMocking() + doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } + + testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob()) + shellInit = spy(ShellInit(testExecutor)) + + whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks } + whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout) + whenever(displayLayout.getStableBounds(any())).thenAnswer { i -> + (i.arguments.first() as Rect).set(STABLE_BOUNDS) + } + val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) + tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN + whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(tda) + + doAnswer { + keyGestureEventHandler = (it.arguments[0] as KeyGestureEventHandler) + null + }.whenever(inputManager).registerKeyGestureEventHandler(any()) + shellInit.init() + } + + @After + fun tearDown() { + mockitoSession.finishMocking() + + runningTasks.clear() + testScope.cancel() + } + + @Test + @EnableFlags( + FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS, + FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT, + FLAG_USE_KEY_GESTURE_EVENT_HANDLER + ) + fun keyGestureMoveToNextDisplay_shouldMoveToNextDisplay() { + desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler( + context, + Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController), + inputManager, shellTaskOrganizer, focusTransitionObserver + ) + // Set up two display ids + whenever(rootTaskDisplayAreaOrganizer.displayIds) + .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) + // Create a mock for the target display area: default display + val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) + whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) + .thenReturn(defaultDisplayArea) + // Setup a focused task on secondary display, which is expected to move to default display + val task = setUpFreeformTask(displayId = SECOND_DISPLAY) + task.isFocused = true + whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task)) + whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true) + + val event = KeyGestureEvent.Builder() + .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY) + .setDisplayId(SECOND_DISPLAY) + .setKeycodes(intArrayOf(KeyEvent.KEYCODE_D)) + .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON) + .build() + val result = keyGestureEventHandler.handleKeyGestureEvent(event, null) + + assertThat(result).isTrue() + verify(desktopTasksController).moveToNextDisplay(task.taskId) + } + + @Test + @EnableFlags( + FLAG_USE_KEY_GESTURE_EVENT_HANDLER, + FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS + ) + fun keyGestureSnapLeft_shouldSnapResizeTaskToLeft() { + desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler( + context, + Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController), + inputManager, shellTaskOrganizer, focusTransitionObserver + ) + val task = setUpFreeformTask() + task.isFocused = true + whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task)) + whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true) + + val event = KeyGestureEvent.Builder() + .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW) + .setKeycodes(intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET)) + .setModifierState(KeyEvent.META_META_ON) + .build() + val result = keyGestureEventHandler.handleKeyGestureEvent(event, null) + + assertThat(result).isTrue() + verify(desktopModeWindowDecorViewModel).onSnapResize(task.taskId, true, null) + } + + @Test + @EnableFlags( + FLAG_USE_KEY_GESTURE_EVENT_HANDLER, + FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS + ) + fun keyGestureSnapRight_shouldSnapResizeTaskToRight() { + desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler( + context, + Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController), + inputManager, shellTaskOrganizer, focusTransitionObserver + ) + val task = setUpFreeformTask() + task.isFocused = true + whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task)) + whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true) + + val event = KeyGestureEvent.Builder() + .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW) + .setKeycodes(intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET)) + .setModifierState(KeyEvent.META_META_ON) + .build() + val result = keyGestureEventHandler.handleKeyGestureEvent(event, null) + + assertThat(result).isTrue() + verify(desktopModeWindowDecorViewModel).onSnapResize(task.taskId, false, null) + } + + @Test + @EnableFlags( + FLAG_USE_KEY_GESTURE_EVENT_HANDLER, + FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS + ) + fun keyGestureToggleFreeformWindowSize_shouldToggleTaskSize() { + desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler( + context, + Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController), + inputManager, shellTaskOrganizer, focusTransitionObserver + ) + val task = setUpFreeformTask() + task.isFocused = true + whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task)) + whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true) + + val event = KeyGestureEvent.Builder() + .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW) + .setKeycodes(intArrayOf(KeyEvent.KEYCODE_EQUALS)) + .setModifierState(KeyEvent.META_META_ON) + .build() + val result = keyGestureEventHandler.handleKeyGestureEvent(event, null) + + assertThat(result).isTrue() + verify(desktopTasksController).toggleDesktopTaskSize( + task, + ResizeTrigger.MAXIMIZE_MENU, + null + ) + } + + @Test + @EnableFlags( + FLAG_USE_KEY_GESTURE_EVENT_HANDLER, + FLAG_ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS + ) + fun keyGestureMinimizeFreeformWindow_shouldMinimizeTask() { + desktopModeKeyGestureHandler = DesktopModeKeyGestureHandler( + context, + Optional.of(desktopModeWindowDecorViewModel), Optional.of(desktopTasksController), + inputManager, shellTaskOrganizer, focusTransitionObserver + ) + val task = setUpFreeformTask() + task.isFocused = true + whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task)) + whenever(focusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true) + + val event = KeyGestureEvent.Builder() + .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW) + .setKeycodes(intArrayOf(KeyEvent.KEYCODE_MINUS)) + .setModifierState(KeyEvent.META_META_ON) + .build() + val result = keyGestureEventHandler.handleKeyGestureEvent(event, null) + + assertThat(result).isTrue() + verify(desktopTasksController).minimizeTask(task) + } + + private fun setUpFreeformTask( + displayId: Int = DEFAULT_DISPLAY, + bounds: Rect? = null, + ): RunningTaskInfo { + val task = createFreeformTask(displayId, bounds) + val activityInfo = ActivityInfo() + task.topActivityInfo = activityInfo + whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) + runningTasks.add(task) + return task + } + + private companion object { + const val SECOND_DISPLAY = 2 + val STABLE_BOUNDS = Rect(0, 0, 1000, 1000) + } +} 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 ad266ead774e..93999476316a 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 @@ -36,12 +36,10 @@ import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT import android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED import android.content.res.Configuration.ORIENTATION_LANDSCAPE import android.content.res.Configuration.ORIENTATION_PORTRAIT +import android.content.res.Resources import android.graphics.Point import android.graphics.PointF import android.graphics.Rect -import android.hardware.input.InputManager -import android.hardware.input.InputManager.KeyGestureEventHandler -import android.hardware.input.KeyGestureEvent import android.os.Binder import android.os.Bundle import android.os.Handler @@ -53,7 +51,6 @@ import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import android.view.DragEvent import android.view.Gravity -import android.view.KeyEvent import android.view.MotionEvent import android.view.SurfaceControl import android.view.WindowInsets @@ -63,6 +60,7 @@ import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_BACK import android.view.WindowManager.TRANSIT_TO_FRONT +import android.widget.Toast import android.window.DisplayAreaInfo import android.window.IWindowContainerToken import android.window.RemoteTransition @@ -75,18 +73,14 @@ import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_R import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER import android.window.WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_TASK_ID import androidx.test.filters.SmallTest -import com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession import com.android.dx.mockito.inline.extended.ExtendedMockito.never import com.android.dx.mockito.inline.extended.StaticMockitoSession -import com.android.hardware.input.Flags.FLAG_USE_KEY_GESTURE_EVENT_HANDLER import com.android.internal.jank.InteractionJankMonitor import com.android.window.flags.Flags import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE -import com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS import com.android.window.flags.Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP -import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT import com.android.wm.shell.MockToken import com.android.wm.shell.R import com.android.wm.shell.RootTaskDisplayAreaOrganizer @@ -96,10 +90,10 @@ import com.android.wm.shell.TestRunningTaskInfoBuilder import com.android.wm.shell.TestShellExecutor import com.android.wm.shell.common.DisplayController import com.android.wm.shell.common.DisplayLayout -import com.android.wm.shell.common.LaunchAdjacentController import com.android.wm.shell.common.MultiInstanceHelper import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.common.SyncTransactionQueue +import com.android.wm.shell.desktopmode.DesktopImmersiveController.ExitResult import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeTrigger import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition import com.android.wm.shell.desktopmode.DesktopTasksController.TaskbarDesktopTaskListener @@ -123,7 +117,6 @@ import com.android.wm.shell.splitscreen.SplitScreenController import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellController import com.android.wm.shell.sysui.ShellInit -import com.android.wm.shell.transition.FocusTransitionObserver import com.android.wm.shell.transition.OneShotRemoteHandler import com.android.wm.shell.transition.TestRemoteTransition import com.android.wm.shell.transition.Transitions @@ -167,6 +160,7 @@ import org.mockito.Mockito.verify import org.mockito.Mockito.times import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.atLeastOnce import org.mockito.kotlin.capture import org.mockito.kotlin.eq @@ -206,12 +200,10 @@ class DesktopTasksControllerTest : ShellTestCase() { @Mock lateinit var dragToDesktopTransitionHandler: DragToDesktopTransitionHandler @Mock lateinit var mMockDesktopImmersiveController: DesktopImmersiveController - @Mock lateinit var launchAdjacentController: LaunchAdjacentController @Mock lateinit var splitScreenController: SplitScreenController @Mock lateinit var recentsTransitionHandler: RecentsTransitionHandler @Mock lateinit var dragAndDropController: DragAndDropController @Mock lateinit var multiInstanceHelper: MultiInstanceHelper - @Mock lateinit var desktopModeLoggerTransitionObserver: DesktopModeLoggerTransitionObserver @Mock lateinit var desktopModeVisualIndicator: DesktopModeVisualIndicator @Mock lateinit var recentTasksController: RecentTasksController @Mock @@ -222,23 +214,21 @@ class DesktopTasksControllerTest : ShellTestCase() { @Mock private lateinit var mockHandler: Handler @Mock private lateinit var desktopModeEventLogger: DesktopModeEventLogger @Mock lateinit var persistentRepository: DesktopPersistentRepository - @Mock private lateinit var mockInputManager: InputManager - @Mock private lateinit var mockFocusTransitionObserver: FocusTransitionObserver @Mock lateinit var motionEvent: MotionEvent @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer - + @Mock private lateinit var mockToast: Toast private lateinit var mockitoSession: StaticMockitoSession @Mock private lateinit var desktopTilingDecorViewModel: DesktopTilingDecorViewModel @Mock private lateinit var desktopWindowDecoration: DesktopModeWindowDecoration + @Mock private lateinit var resources: Resources private lateinit var controller: DesktopTasksController private lateinit var shellInit: ShellInit private lateinit var taskRepository: DesktopRepository private lateinit var desktopTasksLimiter: DesktopTasksLimiter private lateinit var recentsTransitionStateListener: RecentsTransitionStateListener private lateinit var testScope: CoroutineScope - private lateinit var keyGestureEventHandler: KeyGestureEventHandler private val shellExecutor = TestShellExecutor() @@ -261,6 +251,7 @@ class DesktopTasksControllerTest : ShellTestCase() { mockitoSession() .strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java) + .spyStatic(Toast::class.java) .startMocking() doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) } @@ -288,26 +279,22 @@ class DesktopTasksControllerTest : ShellTestCase() { whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }).thenReturn( Desktop.getDefaultInstance() ) + doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) } val tda = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) tda.configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FULLSCREEN whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)).thenReturn(tda) whenever(mMockDesktopImmersiveController .exitImmersiveIfApplicable(any(), any<RunningTaskInfo>())) - .thenReturn(DesktopImmersiveController.ExitResult.NoExit) + .thenReturn(ExitResult.NoExit) whenever(mMockDesktopImmersiveController .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull())) - .thenReturn(DesktopImmersiveController.ExitResult.NoExit) + .thenReturn(ExitResult.NoExit) controller = createController() controller.setSplitScreenController(splitScreenController) controller.freeformTaskTransitionStarter = freeformTaskTransitionStarter - doAnswer { - keyGestureEventHandler = (it.arguments[0] as KeyGestureEventHandler) - null - }.whenever(mockInputManager).registerKeyGestureEventHandler(any()) - shellInit.init() val captor = ArgumentCaptor.forClass(RecentsTransitionStateListener::class.java) @@ -341,8 +328,6 @@ class DesktopTasksControllerTest : ShellTestCase() { dragToDesktopTransitionHandler, mMockDesktopImmersiveController, taskRepository, - desktopModeLoggerTransitionObserver, - launchAdjacentController, recentsTransitionHandler, multiInstanceHelper, shellExecutor, @@ -350,8 +335,6 @@ class DesktopTasksControllerTest : ShellTestCase() { recentTasksController, mockInteractionJankMonitor, mockHandler, - mockInputManager, - mockFocusTransitionObserver, desktopModeEventLogger, desktopTilingDecorViewModel, ) @@ -1556,44 +1539,6 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test - @EnableFlags( - FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS, - FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT, - FLAG_USE_KEY_GESTURE_EVENT_HANDLER - ) - fun moveToNextDisplay_withKeyGesture() { - // Set up two display ids - whenever(rootTaskDisplayAreaOrganizer.displayIds) - .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY)) - // Create a mock for the target display area: default display - val defaultDisplayArea = DisplayAreaInfo(MockToken().token(), DEFAULT_DISPLAY, 0) - whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY)) - .thenReturn(defaultDisplayArea) - // Setup a focused task on secondary display, which is expected to move to default display - val task = setUpFreeformTask(displayId = SECOND_DISPLAY) - task.isFocused = true - whenever(shellTaskOrganizer.getRunningTasks()).thenReturn(arrayListOf(task)) - whenever(mockFocusTransitionObserver.hasGlobalFocus(eq(task))).thenReturn(true) - - val event = KeyGestureEvent.Builder() - .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_MOVE_TO_NEXT_DISPLAY) - .setDisplayId(SECOND_DISPLAY) - .setKeycodes(intArrayOf(KeyEvent.KEYCODE_D)) - .setModifierState(KeyEvent.META_META_ON or KeyEvent.META_CTRL_ON) - .build() - val result = keyGestureEventHandler.handleKeyGestureEvent(event, null) - - assertThat(result).isTrue() - with(getLatestWct(type = TRANSIT_CHANGE)) { - assertThat(hierarchyOps).hasSize(1) - assertThat(hierarchyOps[0].container).isEqualTo(task.token.asBinder()) - assertThat(hierarchyOps[0].isReparent).isTrue() - assertThat(hierarchyOps[0].newParent).isEqualTo(defaultDisplayArea.token.asBinder()) - assertThat(hierarchyOps[0].toTop).isTrue() - } - } - - @Test fun getTaskWindowingMode() { val fullscreenTask = setUpFullscreenTask() val freeformTask = setUpFreeformTask() @@ -1833,7 +1778,8 @@ class DesktopTasksControllerTest : ShellTestCase() { whenever(freeformTaskTransitionStarter.startMinimizedModeTransition(any())) .thenReturn(transition) whenever(mMockDesktopImmersiveController.exitImmersiveIfApplicable(any(), eq(task))) - .thenReturn(DesktopImmersiveController.ExitResult.Exit( + .thenReturn( + ExitResult.Exit( exitingTask = task.taskId, runOnTransitionStart = runOnTransit, )) @@ -3214,13 +3160,43 @@ class DesktopTasksControllerTest : ShellTestCase() { fun newWindow_fromFreeformAddsNewWindow() { setUpLandscapeDisplay() val task = setUpFreeformTask() - val wctCaptor = ArgumentCaptor.forClass(WindowContainerTransaction::class.java) + val wctCaptor = argumentCaptor<WindowContainerTransaction>() + val transition = Binder() + whenever(mMockDesktopImmersiveController + .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull())) + .thenReturn(ExitResult.NoExit) + whenever(desktopMixedTransitionHandler + .startLaunchTransition(anyInt(), any(), anyOrNull(), anyOrNull(), anyOrNull())) + .thenReturn(transition) + runOpenNewWindow(task) - verify(transitions).startTransition(anyInt(), wctCaptor.capture(), anyOrNull()) - assertThat(ActivityOptions.fromBundle(wctCaptor.value.hierarchyOps[0].launchOptions) + + verify(desktopMixedTransitionHandler) + .startLaunchTransition(anyInt(), wctCaptor.capture(), anyOrNull(), anyOrNull(), anyOrNull()) + assertThat(ActivityOptions.fromBundle(wctCaptor.firstValue.hierarchyOps[0].launchOptions) .launchWindowingMode).isEqualTo(WINDOWING_MODE_FREEFORM) } + @Test + @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES) + fun newWindow_fromFreeform_exitsImmersiveIfNeeded() { + setUpLandscapeDisplay() + val immersiveTask = setUpFreeformTask() + val task = setUpFreeformTask() + val runOnStart = RunOnStartTransitionCallback() + val transition = Binder() + whenever(mMockDesktopImmersiveController + .exitImmersiveIfApplicable(any(), anyInt(), anyOrNull())) + .thenReturn(ExitResult.Exit(immersiveTask.taskId, runOnStart)) + whenever(desktopMixedTransitionHandler + .startLaunchTransition(anyInt(), any(), anyOrNull(), anyOrNull(), anyOrNull())) + .thenReturn(transition) + + runOpenNewWindow(task) + + runOnStart.assertOnlyInvocation(transition) + } + private fun runOpenNewWindow(task: RunningTaskInfo) { markTaskVisible(task) task.baseActivity = mock(ComponentName::class.java) @@ -3314,7 +3290,8 @@ class DesktopTasksControllerTest : ShellTestCase() { .thenReturn(transition) whenever(mMockDesktopImmersiveController .exitImmersiveIfApplicable(any(), eq(immersiveTask.displayId), eq(freeformTask.taskId))) - .thenReturn(DesktopImmersiveController.ExitResult.Exit( + .thenReturn( + ExitResult.Exit( exitingTask = immersiveTask.taskId, runOnTransitionStart = runOnStartTransit, )) @@ -3431,7 +3408,7 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING, Flags.FLAG_ENABLE_TILE_RESIZING) - fun handleSnapResizingTask_nonResizable_snapsToHalfScreen() { + fun handleSnapResizingTaskOnDrag_nonResizable_snapsToHalfScreen() { val task = setUpFreeformTask(DEFAULT_DISPLAY, Rect(0, 0, 200, 100)).apply { isResizeable = false } @@ -3440,7 +3417,7 @@ class DesktopTasksControllerTest : ShellTestCase() { val expectedBounds = Rect(STABLE_BOUNDS.left, STABLE_BOUNDS.top, STABLE_BOUNDS.right / 2, STABLE_BOUNDS.bottom) - controller.handleSnapResizingTask( + controller.handleSnapResizingTaskOnDrag( task, SnapPosition.LEFT, mockSurface, currentDragBounds, preDragBounds, motionEvent, desktopWindowDecoration @@ -3459,14 +3436,14 @@ class DesktopTasksControllerTest : ShellTestCase() { @Test @EnableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING) - fun handleSnapResizingTask_nonResizable_startsRepositionAnimation() { + fun handleSnapResizingTaskOnDrag_nonResizable_startsRepositionAnimation() { val task = setUpFreeformTask(DEFAULT_DISPLAY, Rect(0, 0, 200, 100)).apply { isResizeable = false } val preDragBounds = Rect(100, 100, 400, 500) val currentDragBounds = Rect(0, 100, 300, 500) - controller.handleSnapResizingTask( + controller.handleSnapResizingTaskOnDrag( task, SnapPosition.LEFT, mockSurface, currentDragBounds, preDragBounds, motionEvent, desktopWindowDecoration) verify(mReturnToDragStartAnimator).start( @@ -3486,6 +3463,59 @@ class DesktopTasksControllerTest : ShellTestCase() { } @Test + @EnableFlags( + Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING + ) + fun handleInstantSnapResizingTask_nonResizable_animatorNotStartedAndShowsToast() { + val taskBounds = Rect(0, 0, 200, 100) + val task = setUpFreeformTask(DEFAULT_DISPLAY, taskBounds).apply { + isResizeable = false + } + + controller.handleInstantSnapResizingTask( + task, SnapPosition.LEFT, ResizeTrigger.SNAP_LEFT_MENU, motionEvent, desktopWindowDecoration) + + // Assert that task is NOT updated via WCT + verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any()) + verify(mockToast).show() + } + + @Test + @EnableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING) + @DisableFlags(Flags.FLAG_ENABLE_TILE_RESIZING) + fun handleInstantSnapResizingTask_resizable_snapsToHalfScreenAndNotShowToast() { + val taskBounds = Rect(0, 0, 200, 100) + val task = setUpFreeformTask(DEFAULT_DISPLAY, taskBounds).apply { + isResizeable = true + } + val expectedBounds = Rect( + STABLE_BOUNDS.left, STABLE_BOUNDS.top, STABLE_BOUNDS.right / 2, STABLE_BOUNDS.bottom + ) + + controller.handleInstantSnapResizingTask( + task, SnapPosition.LEFT, ResizeTrigger.SNAP_LEFT_MENU, motionEvent, desktopWindowDecoration) + + // Assert bounds set to half of the stable bounds + val wct = getLatestToggleResizeDesktopTaskWct(taskBounds) + assertThat(findBoundsChange(wct, task)).isEqualTo(expectedBounds) + verify(mockToast, never()).show() + verify(desktopModeEventLogger, times(1)).logTaskResizingStarted( + ResizeTrigger.SNAP_LEFT_MENU, + motionEvent, + task, + displayController + ) + verify(desktopModeEventLogger, times(1)).logTaskResizingEnded( + ResizeTrigger.SNAP_LEFT_MENU, + motionEvent, + task, + expectedBounds.height(), + expectedBounds.width(), + displayController + ) + } + + @Test fun toggleBounds_togglesToCalculatedBoundsForNonResizable() { val bounds = Rect(0, 0, 200, 100) val task = setUpFreeformTask(DEFAULT_DISPLAY, bounds).apply { @@ -3719,7 +3749,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val transition = Binder() whenever(mMockDesktopImmersiveController .exitImmersiveIfApplicable(wct, task.displayId, task.taskId)) - .thenReturn(DesktopImmersiveController.ExitResult.Exit( + .thenReturn( + ExitResult.Exit( exitingTask = 5, runOnTransitionStart = runOnStartTransit, )) @@ -3740,7 +3771,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val transition = Binder() whenever(mMockDesktopImmersiveController .exitImmersiveIfApplicable(wct, task.displayId, task.taskId)) - .thenReturn(DesktopImmersiveController.ExitResult.Exit( + .thenReturn( + ExitResult.Exit( exitingTask = 5, runOnTransitionStart = runOnStartTransit, )) @@ -3760,7 +3792,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val transition = Binder() whenever(mMockDesktopImmersiveController .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId))) - .thenReturn(DesktopImmersiveController.ExitResult.Exit( + .thenReturn( + ExitResult.Exit( exitingTask = 5, runOnTransitionStart = runOnStartTransit, )) @@ -3782,7 +3815,8 @@ class DesktopTasksControllerTest : ShellTestCase() { val transition = Binder() whenever(mMockDesktopImmersiveController .exitImmersiveIfApplicable(any(), eq(task.displayId), eq(task.taskId))) - .thenReturn(DesktopImmersiveController.ExitResult.Exit( + .thenReturn( + ExitResult.Exit( exitingTask = 5, runOnTransitionStart = runOnStartTransit, )) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java index a4008c1e6995..72c466663a56 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipEnterAnimatorTest.java @@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; @@ -39,6 +40,7 @@ import android.view.SurfaceControl; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.wm.shell.R; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import com.android.wm.shell.pip2.phone.PipAppIconOverlay; @@ -49,33 +51,25 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** - * Unit test again {@link PipEnterAnimator}. + * Unit test against {@link PipEnterAnimator}. */ @SmallTest @TestableLooper.RunWithLooper @RunWith(AndroidTestingRunner.class) public class PipEnterAnimatorTest { + private static final float TEST_CORNER_RADIUS = 1f; + private static final float TEST_SHADOW_RADIUS = 2f; @Mock private Context mMockContext; - @Mock private Resources mMockResources; - @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory; - @Mock private SurfaceControl.Transaction mMockAnimateTransaction; - @Mock private SurfaceControl.Transaction mMockStartTransaction; - @Mock private SurfaceControl.Transaction mMockFinishTransaction; - @Mock private Runnable mMockStartCallback; - @Mock private Runnable mMockEndCallback; - @Mock private PipAppIconOverlay mMockPipAppIconOverlay; - @Mock private SurfaceControl mMockAppIconOverlayLeash; - @Mock private ActivityInfo mMockActivityInfo; @Surface.Rotation private int mRotation; @@ -89,13 +83,15 @@ public class PipEnterAnimatorTest { when(mMockContext.getResources()).thenReturn(mMockResources); when(mMockResources.getInteger(anyInt())).thenReturn(0); when(mMockFactory.getTransaction()).thenReturn(mMockAnimateTransaction); - when(mMockAnimateTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any())) - .thenReturn(mMockAnimateTransaction); - when(mMockStartTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any())) - .thenReturn(mMockStartTransaction); - when(mMockFinishTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any())) - .thenReturn(mMockFinishTransaction); when(mMockPipAppIconOverlay.getLeash()).thenReturn(mMockAppIconOverlayLeash); + when(mMockResources.getDimensionPixelSize(R.dimen.pip_corner_radius)) + .thenReturn((int) TEST_CORNER_RADIUS); + when(mMockResources.getDimensionPixelSize(R.dimen.pip_shadow_radius)) + .thenReturn((int) TEST_SHADOW_RADIUS); + + prepareTransaction(mMockAnimateTransaction); + prepareTransaction(mMockStartTransaction); + prepareTransaction(mMockFinishTransaction); mTestLeash = new SurfaceControl.Builder() .setContainerLayer() @@ -122,6 +118,12 @@ public class PipEnterAnimatorTest { verify(mMockStartCallback).run(); verifyZeroInteractions(mMockEndCallback); + + // Check corner and shadow radii were set + verify(mMockAnimateTransaction, atLeastOnce()) + .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS)); + verify(mMockAnimateTransaction, atLeastOnce()) + .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS)); } @Test @@ -142,6 +144,12 @@ public class PipEnterAnimatorTest { verify(mMockStartCallback).run(); verify(mMockEndCallback).run(); + + // Check corner and shadow radii were set + verify(mMockAnimateTransaction, atLeastOnce()) + .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS)); + verify(mMockAnimateTransaction, atLeastOnce()) + .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS)); } @Test @@ -197,5 +205,21 @@ public class PipEnterAnimatorTest { verify(mMockPipAppIconOverlay).onAnimationUpdate( eq(mMockAnimateTransaction), anyFloat(), eq(fraction), eq(mEndBounds)); + + // Check corner and shadow radii were set + verify(mMockAnimateTransaction, atLeastOnce()) + .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS)); + verify(mMockAnimateTransaction, atLeastOnce()) + .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS)); + } + + // set up transaction chaining + private void prepareTransaction(SurfaceControl.Transaction tx) { + when(tx.setMatrix(any(SurfaceControl.class), any(Matrix.class), any())) + .thenReturn(tx); + when(tx.setCornerRadius(any(SurfaceControl.class), anyFloat())) + .thenReturn(tx); + when(tx.setShadowRadius(any(SurfaceControl.class), anyFloat())) + .thenReturn(tx); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java index 0adb50b81896..23fbad05ec99 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipResizeAnimatorTest.java @@ -16,15 +16,18 @@ package com.android.wm.shell.pip2.animation; +import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static org.mockito.kotlin.MatchersKt.eq; -import static org.junit.Assert.assertEquals; import android.content.Context; +import android.content.res.Resources; import android.graphics.Matrix; import android.graphics.Rect; import android.testing.AndroidTestingRunner; @@ -34,12 +37,14 @@ import android.view.SurfaceControl; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.wm.shell.R; import com.android.wm.shell.pip2.PipSurfaceTransactionHelper; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -52,40 +57,40 @@ import org.mockito.MockitoAnnotations; public class PipResizeAnimatorTest { private static final float FLOAT_COMPARISON_DELTA = 0.001f; + private static final float TEST_CORNER_RADIUS = 1f; + private static final float TEST_SHADOW_RADIUS = 2f; @Mock private Context mMockContext; - + @Mock private Resources mMockResources; @Mock private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mMockFactory; - @Mock private SurfaceControl.Transaction mMockTransaction; - @Mock private SurfaceControl.Transaction mMockStartTransaction; - @Mock private SurfaceControl.Transaction mMockFinishTransaction; - @Mock private Runnable mMockStartCallback; - @Mock private Runnable mMockEndCallback; + @Captor private ArgumentCaptor<Matrix> mArgumentCaptor; + private PipResizeAnimator mPipResizeAnimator; private Rect mBaseBounds; private Rect mStartBounds; private Rect mEndBounds; private SurfaceControl mTestLeash; - private ArgumentCaptor<Matrix> mArgumentCaptor; @Before public void setUp() { MockitoAnnotations.initMocks(this); when(mMockFactory.getTransaction()).thenReturn(mMockTransaction); - when(mMockTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any())) - .thenReturn(mMockTransaction); - when(mMockStartTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any())) - .thenReturn(mMockStartTransaction); - when(mMockFinishTransaction.setMatrix(any(SurfaceControl.class), any(Matrix.class), any())) - .thenReturn(mMockFinishTransaction); - - mArgumentCaptor = ArgumentCaptor.forClass(Matrix.class); + when(mMockContext.getResources()).thenReturn(mMockResources); + when(mMockResources.getDimensionPixelSize(R.dimen.pip_corner_radius)) + .thenReturn((int) TEST_CORNER_RADIUS); + when(mMockResources.getDimensionPixelSize(R.dimen.pip_shadow_radius)) + .thenReturn((int) TEST_SHADOW_RADIUS); + + prepareTransaction(mMockTransaction); + prepareTransaction(mMockStartTransaction); + prepareTransaction(mMockFinishTransaction); + mTestLeash = new SurfaceControl.Builder() .setContainerLayer() .setName("PipResizeAnimatorTest") @@ -187,6 +192,12 @@ public class PipResizeAnimatorTest { assertEquals(matrix[Matrix.MSCALE_Y], 1f, FLOAT_COMPARISON_DELTA); assertEquals(matrix[Matrix.MTRANS_X], mEndBounds.left, FLOAT_COMPARISON_DELTA); assertEquals(matrix[Matrix.MTRANS_Y], mEndBounds.top, FLOAT_COMPARISON_DELTA); + + // Check corner and shadow radii were set + verify(mMockTransaction, atLeastOnce()) + .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS)); + verify(mMockTransaction, atLeastOnce()) + .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS)); } @Test @@ -237,6 +248,12 @@ public class PipResizeAnimatorTest { assertEquals(matrix[Matrix.MSCALE_Y], 1f, FLOAT_COMPARISON_DELTA); assertEquals(matrix[Matrix.MTRANS_X], mEndBounds.left, FLOAT_COMPARISON_DELTA); assertEquals(matrix[Matrix.MTRANS_Y], mEndBounds.top, FLOAT_COMPARISON_DELTA); + + // Check corner and shadow radii were set + verify(mMockTransaction, atLeastOnce()) + .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS)); + verify(mMockTransaction, atLeastOnce()) + .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS)); } @Test @@ -272,5 +289,21 @@ public class PipResizeAnimatorTest { mArgumentCaptor.getValue().getValues(matrix); assertEquals(matrix[Matrix.MSKEW_X], 0f, FLOAT_COMPARISON_DELTA); assertEquals(matrix[Matrix.MSKEW_Y], 0f, FLOAT_COMPARISON_DELTA); + + // Check corner and shadow radii were set + verify(mMockTransaction, atLeastOnce()) + .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS)); + verify(mMockTransaction, atLeastOnce()) + .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS)); + } + + // set up transaction chaining + private void prepareTransaction(SurfaceControl.Transaction tx) { + when(tx.setMatrix(any(SurfaceControl.class), any(Matrix.class), any())) + .thenReturn(tx); + when(tx.setCornerRadius(any(SurfaceControl.class), anyFloat())) + .thenReturn(tx); + when(tx.setShadowRadius(any(SurfaceControl.class), anyFloat())) + .thenReturn(tx); } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt index 2b30bc360d06..fd3adabfd44b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedTaskInfoTest.kt @@ -176,6 +176,30 @@ class GroupedTaskInfoTest : ShellTestCase() { assertThat(recentTaskInfoParcel.minimizedTaskIds).isEqualTo(arrayOf(2).toIntArray()) } + @Test + fun testGetTaskById_singleTasks() { + val task1 = createTaskInfo(id = 1234) + + val taskInfo = GroupedTaskInfo.forFullscreenTasks(task1) + + assertThat(taskInfo.getTaskById(1234)).isEqualTo(task1) + assertThat(taskInfo.containsTask(1234)).isTrue() + } + + @Test + fun testGetTaskById_multipleTasks() { + val task1 = createTaskInfo(id = 1) + val task2 = createTaskInfo(id = 2) + val splitBounds = SplitBounds(Rect(), Rect(), 1, 2, SNAP_TO_2_50_50) + + val taskInfo = GroupedTaskInfo.forSplitTasks(task1, task2, splitBounds) + + assertThat(taskInfo.getTaskById(1)).isEqualTo(task1) + assertThat(taskInfo.getTaskById(2)).isEqualTo(task2) + assertThat(taskInfo.containsTask(1)).isTrue() + assertThat(taskInfo.containsTask(2)).isTrue() + } + private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply { taskId = id token = WindowContainerToken(mock(IWindowContainerToken::class.java)) diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java index dede583ca970..12c397868f5a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java @@ -610,7 +610,7 @@ public class RecentTasksControllerTest extends ShellTestCase { mRecentTasksControllerReal.onTaskMovedToFrontThroughTransition(taskInfo); GroupedTaskInfo runningTask = GroupedTaskInfo.forFullscreenTasks(taskInfo); - verify(mRecentTasksListener).onTaskMovedToFront(eq(new GroupedTaskInfo[] { runningTask })); + verify(mRecentTasksListener).onTaskMovedToFront(eq(runningTask)); } @Test @@ -656,6 +656,35 @@ public class RecentTasksControllerTest extends ShellTestCase { assertEquals(splitBounds4, pair2Bounds); } + @Test + @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) + public void shellTopTaskTracker_onTaskStackChanged_expectNoRecentsChanged() throws Exception { + mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener); + mRecentTasksControllerReal.onTaskStackChanged(); + verify(mRecentTasksListener, never()).onRecentTasksChanged(); + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) + public void shellTopTaskTracker_onTaskRemoved_expectNoRecentsChanged() throws Exception { + mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener); + ActivityManager.RunningTaskInfo taskInfo = makeRunningTaskInfo(/* taskId= */10); + mRecentTasksControllerReal.onTaskRemoved(taskInfo); + verify(mRecentTasksListener, never()).onRecentTasksChanged(); + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) + public void shellTopTaskTracker_onVisibleTasksChanged() throws Exception { + mRecentTasksControllerReal.registerRecentTasksListener(mRecentTasksListener); + ActivityManager.RunningTaskInfo taskInfo = makeRunningTaskInfo(/* taskId= */10); + mRecentTasksControllerReal.onVisibleTasksChanged(List.of(taskInfo)); + verify(mRecentTasksListener, never()).onVisibleTasksChanged(any()); + } + /** * Helper to create a task with a given task id. */ diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt index efe4fb18f273..99194620c313 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/TaskStackTransitionObserverTest.kt @@ -16,21 +16,36 @@ package com.android.wm.shell.recents -import android.app.ActivityManager +import android.app.ActivityManager.RunningTaskInfo +import android.app.TaskInfo import android.app.WindowConfiguration +import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN +import android.app.WindowConfiguration.WINDOWING_MODE_PINNED +import android.content.ComponentName +import android.content.Intent import android.os.IBinder +import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.platform.test.flag.junit.SetFlagsRule import android.testing.AndroidTestingRunner import android.view.SurfaceControl import android.view.WindowManager +import android.view.WindowManager.TRANSIT_CHANGE +import android.view.WindowManager.TRANSIT_CLOSE +import android.view.WindowManager.TRANSIT_FIRST_CUSTOM +import android.view.WindowManager.TRANSIT_OPEN +import android.view.WindowManager.TRANSIT_TO_FRONT import android.window.IWindowContainerToken import android.window.TransitionInfo +import android.window.TransitionInfo.FLAG_MOVED_TO_TOP import android.window.WindowContainerToken import androidx.test.filters.SmallTest import com.android.window.flags.Flags +import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.TestShellExecutor +import com.android.wm.shell.TestSyncExecutor import com.android.wm.shell.common.ShellExecutor +import com.android.wm.shell.sysui.ShellCommandHandler import com.android.wm.shell.sysui.ShellInit import com.android.wm.shell.transition.TransitionInfoBuilder import com.android.wm.shell.transition.Transitions @@ -61,7 +76,10 @@ class TaskStackTransitionObserverTest { @JvmField @Rule val setFlagsRule = SetFlagsRule() @Mock private lateinit var shellInit: ShellInit - @Mock lateinit var testExecutor: ShellExecutor + @Mock private lateinit var shellTaskOrganizerLazy: Lazy<ShellTaskOrganizer> + @Mock private lateinit var shellTaskOrganizer: ShellTaskOrganizer + @Mock private lateinit var shellCommandHandler: ShellCommandHandler + @Mock private lateinit var testExecutor: ShellExecutor @Mock private lateinit var transitionsLazy: Lazy<Transitions> @Mock private lateinit var transitions: Transitions @Mock private lateinit var mockTransitionBinder: IBinder @@ -73,24 +91,23 @@ class TaskStackTransitionObserverTest { MockitoAnnotations.initMocks(this) shellInit = Mockito.spy(ShellInit(testExecutor)) whenever(transitionsLazy.get()).thenReturn(transitions) - transitionObserver = TaskStackTransitionObserver(transitionsLazy, shellInit) - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java) - verify(shellInit) - .addInitCallback(initRunnableCaptor.capture(), same(transitionObserver)) - initRunnableCaptor.value.run() - } else { - transitionObserver.onInit() - } + whenever(shellTaskOrganizerLazy.get()).thenReturn(shellTaskOrganizer) + transitionObserver = TaskStackTransitionObserver(shellInit, shellTaskOrganizerLazy, + shellCommandHandler, transitionsLazy) + + val initRunnableCaptor = ArgumentCaptor.forClass(Runnable::class.java) + verify(shellInit) + .addInitCallback(initRunnableCaptor.capture(), same(transitionObserver)) + initRunnableCaptor.value.run() } @Test - @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) fun testRegistersObserverAtInit() { verify(transitions).registerObserver(same(transitionObserver)) } @Test + @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) fun taskCreated_freeformWindow_listenerNotified() { val listener = TestListener() @@ -98,11 +115,11 @@ class TaskStackTransitionObserverTest { transitionObserver.addTaskStackTransitionObserverListener(listener, executor) val change = createChange( - WindowManager.TRANSIT_OPEN, + TRANSIT_OPEN, createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM) ) val transitionInfo = - TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build() + TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build() callOnTransitionReady(transitionInfo) callOnTransitionFinished() @@ -114,6 +131,7 @@ class TaskStackTransitionObserverTest { } @Test + @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) fun taskCreated_fullscreenWindow_listenerNotified() { val listener = TestListener() @@ -121,11 +139,11 @@ class TaskStackTransitionObserverTest { transitionObserver.addTaskStackTransitionObserverListener(listener, executor) val change = createChange( - WindowManager.TRANSIT_OPEN, - createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN) + TRANSIT_OPEN, + createTaskInfo(1, WINDOWING_MODE_FULLSCREEN) ) val transitionInfo = - TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build() + TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build() callOnTransitionReady(transitionInfo) callOnTransitionFinished() @@ -133,10 +151,11 @@ class TaskStackTransitionObserverTest { assertThat(listener.taskInfoOnTaskMovedToFront.taskId).isEqualTo(1) assertThat(listener.taskInfoOnTaskMovedToFront.windowingMode) - .isEqualTo(WindowConfiguration.WINDOWING_MODE_FULLSCREEN) + .isEqualTo(WINDOWING_MODE_FULLSCREEN) } @Test + @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) fun taskCreated_freeformWindowOnTopOfFreeform_listenerNotified() { val listener = TestListener() @@ -144,7 +163,7 @@ class TaskStackTransitionObserverTest { transitionObserver.addTaskStackTransitionObserverListener(listener, executor) val freeformOpenChange = createChange( - WindowManager.TRANSIT_OPEN, + TRANSIT_OPEN, createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM) ) val freeformReorderChange = @@ -153,7 +172,7 @@ class TaskStackTransitionObserverTest { createTaskInfo(2, WindowConfiguration.WINDOWING_MODE_FREEFORM) ) val transitionInfo = - TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0) + TransitionInfoBuilder(TRANSIT_OPEN, 0) .addChange(freeformOpenChange) .addChange(freeformReorderChange) .build() @@ -169,6 +188,7 @@ class TaskStackTransitionObserverTest { } @Test + @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) fun transitionMerged_withChange_onlyOpenChangeIsNotified() { val listener = TestListener() @@ -178,11 +198,11 @@ class TaskStackTransitionObserverTest { // Create open transition val change = createChange( - WindowManager.TRANSIT_OPEN, + TRANSIT_OPEN, createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM) ) val transitionInfo = - TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build() + TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build() // create change transition to be merged to above transition val mergedChange = @@ -212,6 +232,7 @@ class TaskStackTransitionObserverTest { } @Test + @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) fun transitionMerged_withOpen_lastOpenChangeIsNotified() { val listener = TestListener() @@ -221,20 +242,20 @@ class TaskStackTransitionObserverTest { // Create open transition val change = createChange( - WindowManager.TRANSIT_OPEN, + TRANSIT_OPEN, createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM) ) val transitionInfo = - TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(change).build() + TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(change).build() // create change transition to be merged to above transition val mergedChange = createChange( - WindowManager.TRANSIT_OPEN, + TRANSIT_OPEN, createTaskInfo(2, WindowConfiguration.WINDOWING_MODE_FREEFORM) ) val mergedTransitionInfo = - TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(mergedChange).build() + TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(mergedChange).build() val mergedTransition = Mockito.mock(IBinder::class.java) callOnTransitionReady(transitionInfo) @@ -250,6 +271,7 @@ class TaskStackTransitionObserverTest { } @Test + @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) fun taskChange_freeformWindowToFullscreenWindow_listenerNotified() { val listener = TestListener() @@ -257,11 +279,11 @@ class TaskStackTransitionObserverTest { transitionObserver.addTaskStackTransitionObserverListener(listener, executor) val freeformState = createChange( - WindowManager.TRANSIT_OPEN, + TRANSIT_OPEN, createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM) ) val transitionInfoOpen = - TransitionInfoBuilder(WindowManager.TRANSIT_OPEN, 0).addChange(freeformState).build() + TransitionInfoBuilder(TRANSIT_OPEN, 0).addChange(freeformState).build() callOnTransitionReady(transitionInfoOpen) callOnTransitionFinished() executor.flushAll() @@ -276,7 +298,7 @@ class TaskStackTransitionObserverTest { val fullscreenState = createChange( WindowManager.TRANSIT_CHANGE, - createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN) + createTaskInfo(1, WINDOWING_MODE_FULLSCREEN) ) val transitionInfoChange = TransitionInfoBuilder(WindowManager.TRANSIT_CHANGE, 0) @@ -301,6 +323,7 @@ class TaskStackTransitionObserverTest { } @Test + @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) fun singleTransition_withOpenAndChange_onlyOpenIsNotified() { val listener = TestListener() @@ -310,13 +333,13 @@ class TaskStackTransitionObserverTest { // Creating multiple changes to be fired in a single transition val freeformState = createChange( - mode = WindowManager.TRANSIT_OPEN, + mode = TRANSIT_OPEN, taskInfo = createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FREEFORM) ) val fullscreenState = createChange( mode = WindowManager.TRANSIT_CHANGE, - taskInfo = createTaskInfo(1, WindowConfiguration.WINDOWING_MODE_FULLSCREEN) + taskInfo = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN) ) val transitionInfoWithChanges = @@ -336,6 +359,7 @@ class TaskStackTransitionObserverTest { } @Test + @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) @EnableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) fun singleTransition_withMultipleChanges_listenerNotified_forEachChange() { val listener = TestListener() @@ -349,7 +373,7 @@ class TaskStackTransitionObserverTest { listOf( WindowConfiguration.WINDOWING_MODE_FREEFORM, WindowConfiguration.WINDOW_CONFIG_DISPLAY_ROTATION, - WindowConfiguration.WINDOWING_MODE_FULLSCREEN + WINDOWING_MODE_FULLSCREEN ) .map { change -> createChange( @@ -376,19 +400,259 @@ class TaskStackTransitionObserverTest { } } - class TestListener : TaskStackTransitionObserver.TaskStackTransitionObserverListener { - var taskInfoOnTaskMovedToFront = ActivityManager.RunningTaskInfo() - var taskInfoOnTaskChanged = mutableListOf<ActivityManager.RunningTaskInfo>() + @Test + @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) + fun openTransition_visibleTasksChanged() { + val listener = TestListener() + val executor = TestSyncExecutor() + transitionObserver.addTaskStackTransitionObserverListener(listener, executor) + + // Model an opening task + val firstOpeningTransition = + createTransitionInfo(TRANSIT_OPEN, + listOf( + createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN), + ) + ) + + callOnTransitionReady(firstOpeningTransition) + callOnTransitionFinished() + // Assert that the task is reported visible + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1) + assertVisibleTasks(listener, listOf(1)) + + // Model opening another task + val nextOpeningTransition = + createTransitionInfo(TRANSIT_OPEN, + listOf( + createChange(TRANSIT_OPEN, 2, WINDOWING_MODE_FULLSCREEN), + createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FULLSCREEN), + ) + ) + + callOnTransitionReady(nextOpeningTransition) + // Assert that the visible list from top to bottom is valid (opening, closing) + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2) + assertVisibleTasks(listener, listOf(2, 1)) + + callOnTransitionFinished() + // Assert that after the transition finishes, there is only the opening task remaining + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(3) + assertVisibleTasks(listener, listOf(2)) + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) + fun toFrontTransition_visibleTasksChanged() { + val listener = TestListener() + val executor = TestSyncExecutor() + transitionObserver.addTaskStackTransitionObserverListener(listener, executor) + + // Model an opening task + val firstOpeningTransition = + createTransitionInfo(TRANSIT_OPEN, + listOf( + createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN), + ) + ) + + callOnTransitionReady(firstOpeningTransition) + callOnTransitionFinished() + // Assert that the task is reported visible + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1) + assertVisibleTasks(listener, listOf(1)) + + // Model opening another task + val nextOpeningTransition = + createTransitionInfo(TRANSIT_OPEN, + listOf( + createChange(TRANSIT_OPEN, 2, WINDOWING_MODE_FULLSCREEN), + ) + ) + + callOnTransitionReady(nextOpeningTransition) + callOnTransitionFinished() + // Assert that the visible list from top to bottom is valid + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2) + assertVisibleTasks(listener, listOf(2, 1)) + + // Model the first task moving to front + val toFrontTransition = + createTransitionInfo(TRANSIT_TO_FRONT, + listOf( + createChange(TRANSIT_CHANGE, 1, WINDOWING_MODE_FULLSCREEN, + FLAG_MOVED_TO_TOP), + ) + ) + + callOnTransitionReady(toFrontTransition) + callOnTransitionFinished() + // Assert that the visible list from top to bottom is valid + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(3) + assertVisibleTasks(listener, listOf(1, 2)) + } - override fun onTaskMovedToFrontThroughTransition( - taskInfo: ActivityManager.RunningTaskInfo - ) { + @Test + @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) + fun closeTransition_visibleTasksChanged() { + val listener = TestListener() + val executor = TestSyncExecutor() + transitionObserver.addTaskStackTransitionObserverListener(listener, executor) + + // Model an opening task + val firstOpeningTransition = + createTransitionInfo(TRANSIT_OPEN, + listOf( + createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN), + ) + ) + + callOnTransitionReady(firstOpeningTransition) + callOnTransitionFinished() + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1) + + // Model a closing task + val nextOpeningTransition = + createTransitionInfo(TRANSIT_OPEN, + listOf( + createChange(TRANSIT_CLOSE, 1, WINDOWING_MODE_FULLSCREEN), + ) + ) + + callOnTransitionReady(nextOpeningTransition) + // Assert that the visible list hasn't changed (the close is pending) + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1) + + callOnTransitionFinished() + // Assert that after the transition finishes, there is only the opening task remaining + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2) + assertVisibleTasks(listener, listOf()) + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) + fun changeTransition_visibleTasksUnchanged() { + val listener = TestListener() + val executor = TestSyncExecutor() + transitionObserver.addTaskStackTransitionObserverListener(listener, executor) + + // Model an opening task + val firstOpeningTransition = + createTransitionInfo(TRANSIT_OPEN, + listOf( + createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN), + ) + ) + + callOnTransitionReady(firstOpeningTransition) + callOnTransitionFinished() + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1) + + // Model a closing task + val nextOpeningTransition = + createTransitionInfo( + TRANSIT_FIRST_CUSTOM, + listOf( + createChange(TRANSIT_CHANGE, 1, WINDOWING_MODE_FULLSCREEN), + ) + ) + + callOnTransitionReady(nextOpeningTransition) + // Assert that the visible list hasn't changed + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1) + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) + fun taskVanished_visibleTasksChanged() { + val listener = TestListener() + val executor = TestSyncExecutor() + transitionObserver.addTaskStackTransitionObserverListener(listener, executor) + + // Model an opening task + val firstOpeningTransition = + createTransitionInfo(TRANSIT_OPEN, + listOf( + createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_FULLSCREEN), + ) + ) + + callOnTransitionReady(firstOpeningTransition) + callOnTransitionFinished() + // Assert that the task is reported visible + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1) + assertVisibleTasks(listener, listOf(1)) + + // Trigger task vanished + val removedTaskInfo = createTaskInfo(1, WINDOWING_MODE_FULLSCREEN) + transitionObserver.onTaskVanished(removedTaskInfo) + + // Assert that the visible list is now empty + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2) + assertVisibleTasks(listener, listOf()) + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_TASK_STACK_OBSERVER_IN_SHELL) + @EnableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_SHELL_TOP_TASK_TRACKING) + fun alwaysOnTop_taskIsTopMostVisible() { + val listener = TestListener() + val executor = TestSyncExecutor() + transitionObserver.addTaskStackTransitionObserverListener(listener, executor) + + // Model an opening PIP task + val pipOpeningTransition = + createTransitionInfo(TRANSIT_OPEN, + listOf( + createChange(TRANSIT_OPEN, 1, WINDOWING_MODE_PINNED), + ) + ) + + callOnTransitionReady(pipOpeningTransition) + callOnTransitionFinished() + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(1) + assertVisibleTasks(listener, listOf(1)) + + // Model an opening fullscreen task + val firstOpeningTransition = + createTransitionInfo(TRANSIT_OPEN, + listOf( + createChange(TRANSIT_OPEN, 2, WINDOWING_MODE_FULLSCREEN), + ) + ) + + callOnTransitionReady(firstOpeningTransition) + callOnTransitionFinished() + assertThat(listener.visibleTasksUpdatedCount).isEqualTo(2) + assertVisibleTasks(listener, listOf(1, 2)) + } + + class TestListener : TaskStackTransitionObserver.TaskStackTransitionObserverListener { + // Only used if FLAG_ENABLE_SHELL_TOP_TASK_TRACKING is disabled + var taskInfoOnTaskMovedToFront = RunningTaskInfo() + var taskInfoOnTaskChanged = mutableListOf<RunningTaskInfo>() + // Only used if FLAG_ENABLE_SHELL_TOP_TASK_TRACKING is enabled + var visibleTasks = mutableListOf<TaskInfo>() + var visibleTasksUpdatedCount = 0 + + override fun onTaskMovedToFrontThroughTransition(taskInfo: RunningTaskInfo) { taskInfoOnTaskMovedToFront = taskInfo } - override fun onTaskChangedThroughTransition(taskInfo: ActivityManager.RunningTaskInfo) { + override fun onTaskChangedThroughTransition(taskInfo: RunningTaskInfo) { taskInfoOnTaskChanged += taskInfo } + + override fun onVisibleTasksChanged(visibleTasks: List<RunningTaskInfo>) { + this.visibleTasks.clear() + this.visibleTasks.addAll(visibleTasks) + visibleTasksUpdatedCount++ + } } /** Simulate calling the onTransitionReady() method */ @@ -412,27 +676,64 @@ class TaskStackTransitionObserverTest { transitionObserver.onTransitionMerged(merged, playing) } + /** + * Asserts that the listener has the given expected task ids (in order). + */ + private fun assertVisibleTasks( + listener: TestListener, + expectedVisibleTaskIds: List<Int> + ) { + assertThat(listener.visibleTasks.size).isEqualTo(expectedVisibleTaskIds.size) + expectedVisibleTaskIds.forEachIndexed { index, taskId -> + assertThat(listener.visibleTasks[index].taskId).isEqualTo(taskId) + } + } + companion object { - fun createTaskInfo(taskId: Int, windowingMode: Int): ActivityManager.RunningTaskInfo { - val taskInfo = ActivityManager.RunningTaskInfo() + fun createTaskInfo(taskId: Int, windowingMode: Int): RunningTaskInfo { + val taskInfo = RunningTaskInfo() + taskInfo.baseIntent = Intent().setComponent( + ComponentName(javaClass.packageName, "Test")) taskInfo.taskId = taskId taskInfo.configuration.windowConfiguration.windowingMode = windowingMode - + if (windowingMode == WINDOWING_MODE_PINNED) { + taskInfo.configuration.windowConfiguration.isAlwaysOnTop = true + } return taskInfo } fun createChange( mode: Int, - taskInfo: ActivityManager.RunningTaskInfo + taskInfo: RunningTaskInfo, + flags: Int = 0, ): TransitionInfo.Change { val change = TransitionInfo.Change( WindowContainerToken(Mockito.mock(IWindowContainerToken::class.java)), Mockito.mock(SurfaceControl::class.java) ) + change.flags = flags change.mode = mode change.taskInfo = taskInfo return change } + + fun createChange( + mode: Int, + taskId: Int, + windowingMode: Int, + flags: Int = 0, + ): TransitionInfo.Change { + return createChange(mode, createTaskInfo(taskId, windowingMode), flags) + } + + fun createTransitionInfo( + transitionType: Int, + changes: List<TransitionInfo.Change> + ): TransitionInfo { + return TransitionInfoBuilder(transitionType, 0) + .apply { changes.forEach { c -> this@apply.addChange(c) } } + .build() + } } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java index c36b88e34835..71af97e5add3 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/unfold/UnfoldTransitionHandlerTest.java @@ -43,6 +43,7 @@ import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerTransaction; +import com.android.wm.shell.TestSyncExecutor; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.shared.TransactionPool; import com.android.wm.shell.sysui.ShellInit; @@ -475,27 +476,6 @@ public class UnfoldTransitionHandlerTest { } } - private static class TestSyncExecutor implements ShellExecutor { - @Override - public void execute(Runnable runnable) { - runnable.run(); - } - - @Override - public void executeDelayed(Runnable runnable, long delayMillis) { - runnable.run(); - } - - @Override - public void removeCallbacks(Runnable runnable) { - } - - @Override - public boolean hasCallback(Runnable runnable) { - return false; - } - } - private TransitionInfo createUnfoldTransitionInfo() { TransitionInfo transitionInfo = new TransitionInfo(TRANSIT_CHANGE, /* flags= */ 0); TransitionInfo.Change change = new TransitionInfo.Change(null, mock(SurfaceControl.class)); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt new file mode 100644 index 000000000000..3e26ee0deed0 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/util/TransitionObserverTestUtils.kt @@ -0,0 +1,182 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.wm.shell.util + +import android.app.ActivityManager.RunningTaskInfo +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM +import android.content.ComponentName +import android.content.Intent +import android.os.IBinder +import android.view.Display.DEFAULT_DISPLAY +import android.view.SurfaceControl +import android.view.SurfaceControl.Transaction +import android.view.WindowManager.TRANSIT_NONE +import android.view.WindowManager.TransitionFlags +import android.view.WindowManager.TransitionType +import android.window.IWindowContainerToken +import android.window.TransitionInfo +import android.window.TransitionInfo.Change +import android.window.TransitionInfo.ChangeFlags +import android.window.TransitionInfo.FLAG_NONE +import android.window.TransitionInfo.TransitionMode +import android.window.WindowContainerToken +import com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn +import com.android.wm.shell.transition.Transitions.TransitionObserver +import org.mockito.Mockito +import org.mockito.kotlin.mock + +@DslMarker +annotation class TransitionObserverTagMarker + +/** + * Abstraction for all the phases of the [TransitionObserver] test. + */ +interface TransitionObserverTestStep + +/** + * Encapsulates the values for the [TransitionObserver#onTransitionReady] input parameters. + */ +class TransitionObserverTransitionReadyInput( + val transition: IBinder, + val info: TransitionInfo, + val startTransaction: Transaction, + val finishTransaction: Transaction +) + +@TransitionObserverTagMarker +class TransitionObserverTestContext : TransitionObserverTestStep { + + lateinit var transitionObserver: TransitionObserver + lateinit var transitionReadyInput: TransitionObserverTransitionReadyInput + + fun inputBuilder(builderInput: TransitionObserverInputBuilder.() -> Unit) { + val inputFactoryObj = TransitionObserverInputBuilder() + inputFactoryObj.builderInput() + transitionReadyInput = inputFactoryObj.build() + } + + fun validateOutput( + validate: + TransitionObserverResultValidation.() -> Unit + ) { + val validateObj = TransitionObserverResultValidation() + invokeObservable() + validateObj.validate() + } + + fun invokeObservable() { + transitionObserver.onTransitionReady( + transitionReadyInput.transition, + transitionReadyInput.info, + transitionReadyInput.startTransaction, + transitionReadyInput.finishTransaction + ) + } +} + +/** + * Phase responsible for the input parameters for [TransitionObserver]. + */ +class TransitionObserverInputBuilder : TransitionObserverTestStep { + + private val transition = Mockito.mock(IBinder::class.java) + private var transitionInfo: TransitionInfo? = null + private val startTransaction = Mockito.mock(Transaction::class.java) + private val finishTransaction = Mockito.mock(Transaction::class.java) + + fun buildTransitionInfo( + @TransitionType type: Int = TRANSIT_NONE, + @TransitionFlags flags: Int = 0 + ) { + transitionInfo = TransitionInfo(type, flags) + spyOn(transitionInfo) + } + + fun addChange( + token: WindowContainerToken? = mock(), + leash: SurfaceControl = mock(), + @TransitionMode changeMode: Int = TRANSIT_NONE, + parentToken: WindowContainerToken? = null, + changeTaskInfo: RunningTaskInfo? = null, + @ChangeFlags changeFlags: Int = FLAG_NONE + ) = addChange(Change(token, leash).apply { + mode = changeMode + parent = parentToken + taskInfo = changeTaskInfo + flags = changeFlags + }) + + fun createChange( + token: WindowContainerToken? = mock(), + leash: SurfaceControl = mock(), + @TransitionMode changeMode: Int = TRANSIT_NONE, + parentToken: WindowContainerToken? = null, + changeTaskInfo: RunningTaskInfo? = null, + @ChangeFlags changeFlags: Int = FLAG_NONE + ) = Change(token, leash).apply { + mode = changeMode + parent = parentToken + taskInfo = changeTaskInfo + flags = changeFlags + } + + fun addChange(change: Change) { + transitionInfo!!.addChange(change) + } + + fun createTaskInfo(id: Int = 0, windowingMode: Int = WINDOWING_MODE_FREEFORM) = + RunningTaskInfo().apply { + taskId = id + displayId = DEFAULT_DISPLAY + configuration.windowConfiguration.windowingMode = windowingMode + token = WindowContainerToken(Mockito.mock(IWindowContainerToken::class.java)) + baseIntent = Intent().apply { + component = ComponentName("package", "component.name") + } + } + + fun build(): TransitionObserverTransitionReadyInput = TransitionObserverTransitionReadyInput( + transition = transition, + info = transitionInfo!!, + startTransaction = startTransaction, + finishTransaction = finishTransaction + ) +} + +/** + * Phase responsible for the execution of validation methods. + */ +class TransitionObserverResultValidation : TransitionObserverTestStep + +/** + * Allows to run a test about a specific [TransitionObserver] passing the specific + * implementation and input value as parameters for the [TransitionObserver#onTransitionReady] + * method. + * @param observerFactory The Factory for the TransitionObserver + * @param inputFactory The Builder for the onTransitionReady input parameters + * @param init The test code itself. + */ +fun executeTransitionObserverTest( + observerFactory: () -> TransitionObserver, + init: TransitionObserverTestContext.() -> Unit +): TransitionObserverTestContext { + val testContext = TransitionObserverTestContext().apply { + transitionObserver = observerFactory() + } + testContext.init() + return testContext +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index be664f86e9f5..ef9b30c1c4ca 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -63,7 +63,6 @@ import android.view.SurfaceView import android.view.View import android.view.ViewRootImpl import android.view.WindowInsets.Type.statusBars -import android.widget.Toast import android.window.WindowContainerTransaction import android.window.WindowContainerTransaction.HierarchyOp import androidx.test.filters.SmallTest @@ -186,7 +185,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @Mock private lateinit var mockGenericLinksParser: AppToWebGenericLinksParser @Mock private lateinit var mockUserHandle: UserHandle @Mock private lateinit var mockAssistContentRequester: AssistContentRequester - @Mock private lateinit var mockToast: Toast private val bgExecutor = TestShellExecutor() @Mock private lateinit var mockMultiInstanceHelper: MultiInstanceHelper @Mock private lateinit var mockTasksLimiter: DesktopTasksLimiter @@ -226,7 +224,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { .strictness(Strictness.LENIENT) .spyStatic(DesktopModeStatus::class.java) .spyStatic(DragPositioningCallbackUtility::class.java) - .spyStatic(Toast::class.java) .startMocking() doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(Mockito.any()) } @@ -290,8 +287,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { ) .thenReturn(mockTaskPositioner) - doReturn(mockToast).`when` { Toast.makeText(any(), anyInt(), anyInt()) } - // InputChannel cannot be mocked because it passes to InputEventReceiver. val inputChannels = InputChannel.openInputChannelPair(TAG) inputChannels.first().dispose() @@ -640,7 +635,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @Test fun testOnDecorSnappedLeft_snapResizes() { - val taskSurfaceCaptor = argumentCaptor<SurfaceControl>() val onLeftSnapClickListenerCaptor = forClass(Function0::class.java) as ArgumentCaptor<Function0<Unit>> val decor = createOpenTaskDecoration( @@ -648,19 +642,15 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { onLeftSnapClickListenerCaptor = onLeftSnapClickListenerCaptor ) - val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds onLeftSnapClickListenerCaptor.value.invoke() - verify(mockDesktopTasksController).snapToHalfScreen( + verify(mockDesktopTasksController).handleInstantSnapResizingTask( eq(decor.mTaskInfo), - taskSurfaceCaptor.capture(), - eq(currentBounds), eq(SnapPosition.LEFT), eq(ResizeTrigger.SNAP_LEFT_MENU), eq(null), eq(decor) ) - assertEquals(taskSurfaceCaptor.firstValue, decor.mTaskSurface) } @Test @@ -681,7 +671,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @Test @DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING) fun testOnSnapResizeLeft_nonResizable_decorSnappedLeft() { - val taskSurfaceCaptor = argumentCaptor<SurfaceControl>() val onLeftSnapClickListenerCaptor = forClass(Function0::class.java) as ArgumentCaptor<Function0<Unit>> val decor = createOpenTaskDecoration( @@ -689,19 +678,15 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { onLeftSnapClickListenerCaptor = onLeftSnapClickListenerCaptor ).also { it.mTaskInfo.isResizeable = false } - val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds onLeftSnapClickListenerCaptor.value.invoke() - verify(mockDesktopTasksController).snapToHalfScreen( + verify(mockDesktopTasksController).handleInstantSnapResizingTask( eq(decor.mTaskInfo), - taskSurfaceCaptor.capture(), - eq(currentBounds), eq(SnapPosition.LEFT), eq(ResizeTrigger.SNAP_LEFT_MENU), eq(null), eq(decor), ) - assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue) } @Test @@ -723,12 +708,10 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { eq(null), eq(decor), ) - verify(mockToast).show() } @Test fun testOnDecorSnappedRight_snapResizes() { - val taskSurfaceCaptor = argumentCaptor<SurfaceControl>() val onRightSnapClickListenerCaptor = forClass(Function0::class.java) as ArgumentCaptor<Function0<Unit>> val decor = createOpenTaskDecoration( @@ -736,19 +719,15 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { onRightSnapClickListenerCaptor = onRightSnapClickListenerCaptor ) - val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds onRightSnapClickListenerCaptor.value.invoke() - verify(mockDesktopTasksController).snapToHalfScreen( + verify(mockDesktopTasksController).handleInstantSnapResizingTask( eq(decor.mTaskInfo), - taskSurfaceCaptor.capture(), - eq(currentBounds), eq(SnapPosition.RIGHT), eq(ResizeTrigger.SNAP_RIGHT_MENU), eq(null), eq(decor), ) - assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue) } @Test @@ -769,7 +748,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @Test @DisableFlags(Flags.FLAG_DISABLE_NON_RESIZABLE_APP_SNAP_RESIZING) fun testOnSnapResizeRight_nonResizable_decorSnappedRight() { - val taskSurfaceCaptor = argumentCaptor<SurfaceControl>() val onRightSnapClickListenerCaptor = forClass(Function0::class.java) as ArgumentCaptor<Function0<Unit>> val decor = createOpenTaskDecoration( @@ -777,19 +755,15 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { onRightSnapClickListenerCaptor = onRightSnapClickListenerCaptor ).also { it.mTaskInfo.isResizeable = false } - val currentBounds = decor.mTaskInfo.configuration.windowConfiguration.bounds onRightSnapClickListenerCaptor.value.invoke() - verify(mockDesktopTasksController).snapToHalfScreen( + verify(mockDesktopTasksController).handleInstantSnapResizingTask( eq(decor.mTaskInfo), - taskSurfaceCaptor.capture(), - eq(currentBounds), eq(SnapPosition.RIGHT), eq(ResizeTrigger.SNAP_RIGHT_MENU), eq(null), eq(decor), ) - assertEquals(decor.mTaskSurface, taskSurfaceCaptor.firstValue) } @Test @@ -811,7 +785,6 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { eq(null), eq(decor), ) - verify(mockToast).show() } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index 1d2d0f078817..f653622d0460 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -30,6 +30,7 @@ import static android.view.WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.wm.shell.MockSurfaceControlHelper.createMockSurfaceControlTransaction; import static com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.CLOSE_MAXIMIZE_MENU_DELAY_MS; +import static com.android.wm.shell.windowdecor.WindowDecoration.INVALID_CORNER_RADIUS; import static com.google.common.truth.Truth.assertThat; @@ -219,7 +220,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @Captor private ArgumentCaptor<Runnable> mCloseMaxMenuRunnable; - private final InsetsState mInsetsState = new InsetsState(); + private final InsetsState mInsetsState = createInsetsState(statusBars(), /* visible= */true); private SurfaceControl.Transaction mMockTransaction; private StaticMockitoSession mMockitoSession; private TestableContext mTestableContext; @@ -312,8 +313,9 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { } @Test - public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersAreEnabled() { + public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersSetForFreeform() { final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); + taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM); fillRoundedCornersResources(/* fillValue= */ 30); RelayoutParams relayoutParams = new RelayoutParams(); @@ -334,6 +336,29 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { } @Test + public void updateRelayoutParams_noSysPropFlagsSet_roundedCornersNotSetForFullscreen() { + final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); + taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); + fillRoundedCornersResources(/* fillValue= */ 30); + RelayoutParams relayoutParams = new RelayoutParams(); + + DesktopModeWindowDecoration.updateRelayoutParams( + relayoutParams, + mTestableContext, + taskInfo, + /* applyStartTransactionOnDraw= */ true, + /* shouldSetTaskPositionAndCrop */ false, + /* isStatusBarVisible */ true, + /* isKeyguardVisibleAndOccluded */ false, + /* inFullImmersiveMode */ false, + new InsetsState(), + /* hasGlobalFocus= */ true, + mExclusionRegion); + + assertThat(relayoutParams.mCornerRadius).isEqualTo(INVALID_CORNER_RADIUS); + } + + @Test @EnableFlags(Flags.FLAG_ENABLE_APP_HEADER_WITH_TASK_DENSITY) public void updateRelayoutParams_appHeader_usesTaskDensity() { final int systemDensity = mTestableContext.getOrCreateTestableResources().getResources() @@ -1408,8 +1433,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { public void notifyCaptionStateChanged_flagDisabled_doNoNotify() { when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); - when(mMockDisplayController.getInsetsState(taskInfo.displayId)) - .thenReturn(createInsetsState(statusBars(), /* visible= */true)); final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); @@ -1423,8 +1446,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { public void notifyCaptionStateChanged_inFullscreenMode_notifiesAppHandleVisible() { when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); - when(mMockDisplayController.getInsetsState(taskInfo.displayId)) - .thenReturn(createInsetsState(statusBars(), /* visible= */true)); final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass( @@ -1444,8 +1465,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { public void notifyCaptionStateChanged_inWindowingMode_notifiesAppHeaderVisible() { when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); - when(mMockDisplayController.getInsetsState(taskInfo.displayId)) - .thenReturn(createInsetsState(statusBars(), /* visible= */true)); when(mMockAppHeaderViewHolder.getAppChipLocationInWindow()).thenReturn( new Rect(/* left= */ 0, /* top= */ 1, /* right= */ 2, /* bottom= */ 3)); final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); @@ -1473,8 +1492,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { public void notifyCaptionStateChanged_taskNotVisible_notifiesNoCaptionVisible() { when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ false); - when(mMockDisplayController.getInsetsState(taskInfo.displayId)) - .thenReturn(createInsetsState(statusBars(), /* visible= */true)); final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED); ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass( @@ -1493,8 +1510,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { public void notifyCaptionStateChanged_captionHandleExpanded_notifiesHandleMenuExpanded() { when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); - when(mMockDisplayController.getInsetsState(taskInfo.displayId)) - .thenReturn(createInsetsState(statusBars(), /* visible= */true)); final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass( @@ -1518,8 +1533,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { public void notifyCaptionStateChanged_captionHandleClosed_notifiesHandleMenuClosed() { when(DesktopModeStatus.canEnterDesktopMode(mContext)).thenReturn(true); final ActivityManager.RunningTaskInfo taskInfo = createTaskInfo(/* visible= */ true); - when(mMockDisplayController.getInsetsState(taskInfo.displayId)) - .thenReturn(createInsetsState(statusBars(), /* visible= */true)); final DesktopModeWindowDecoration spyWindowDecor = spy(createWindowDecoration(taskInfo)); taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FULLSCREEN); ArgumentCaptor<CaptionState> captionStateArgumentCaptor = ArgumentCaptor.forClass( diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index fcb7efc35c94..e2db2c9e3827 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -355,6 +355,7 @@ cc_defaults { "jni/AnimatedImageDrawable.cpp", "jni/Bitmap.cpp", "jni/BitmapRegionDecoder.cpp", + "jni/RuntimeXfermode.cpp", "jni/BufferUtils.cpp", "jni/HardwareBufferHelpers.cpp", "jni/BitmapFactory.cpp", diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp index 7c150862a422..7f5ca44f7ceb 100644 --- a/libs/hwui/SkiaCanvas.cpp +++ b/libs/hwui/SkiaCanvas.cpp @@ -622,18 +622,13 @@ bool SkiaCanvas::useGainmapShader(Bitmap& bitmap) { auto colorSpace = info.colorSpace(); // If we don't have a colorspace, we can't apply a gainmap if (!colorSpace) return false; - skcms_TransferFunction tfn; - colorSpace->transferFn(&tfn); - - auto transferType = skcms_TransferFunction_getType(&tfn); - switch (transferType) { - case skcms_TFType_HLGish: - case skcms_TFType_HLGinvish: - case skcms_TFType_PQish: - return true; - case skcms_TFType_Invalid: - case skcms_TFType_sRGBish: - return false; + + const float targetRatio = uirenderer::getTargetHdrSdrRatio(colorSpace); + + if (bitmap.gainmap()->info.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR) { + return targetRatio < bitmap.gainmap()->info.fDisplayRatioHdr; + } else { + return targetRatio > bitmap.gainmap()->info.fDisplayRatioSdr; } } diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp index 15b2bac50c79..56de56805be4 100644 --- a/libs/hwui/apex/jni_runtime.cpp +++ b/libs/hwui/apex/jni_runtime.cpp @@ -28,6 +28,7 @@ extern int register_android_graphics_Bitmap(JNIEnv*); extern int register_android_graphics_BitmapFactory(JNIEnv*); extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*); +extern int register_android_graphics_RuntimeXfermode(JNIEnv*); extern int register_android_graphics_ByteBufferStreamAdaptor(JNIEnv* env); extern int register_android_graphics_Camera(JNIEnv* env); extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env); @@ -107,6 +108,7 @@ extern int register_android_graphics_HardwareBufferRenderer(JNIEnv* env); REG_JNI(register_android_graphics_Bitmap), REG_JNI(register_android_graphics_BitmapFactory), REG_JNI(register_android_graphics_BitmapRegionDecoder), + REG_JNI(register_android_graphics_RuntimeXfermode), REG_JNI(register_android_graphics_ByteBufferStreamAdaptor), REG_JNI(register_android_graphics_Camera), REG_JNI(register_android_graphics_CreateJavaOutputStreamAdaptor), diff --git a/libs/hwui/effects/GainmapRenderer.cpp b/libs/hwui/effects/GainmapRenderer.cpp index eac03609d72f..18b77bc51aca 100644 --- a/libs/hwui/effects/GainmapRenderer.cpp +++ b/libs/hwui/effects/GainmapRenderer.cpp @@ -73,7 +73,9 @@ void DrawGainmapBitmap(SkCanvas* c, const sk_sp<const SkImage>& image, const SkR #ifdef __ANDROID__ auto destColorspace = c->imageInfo().refColorSpace(); float targetSdrHdrRatio = getTargetHdrSdrRatio(destColorspace.get()); - if (targetSdrHdrRatio > 1.f && gainmapImage) { + const bool baseImageHdr = gainmapInfo.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR; + if (gainmapImage && ((baseImageHdr && targetSdrHdrRatio < gainmapInfo.fDisplayRatioHdr) || + (!baseImageHdr && targetSdrHdrRatio > gainmapInfo.fDisplayRatioSdr))) { SkPaint gainmapPaint = *paint; float sX = gainmapImage->width() / (float)image->width(); float sY = gainmapImage->height() / (float)image->height(); @@ -183,7 +185,10 @@ private: baseImage->colorSpace() ? baseImage->refColorSpace() : SkColorSpace::MakeSRGB(); // Determine the color space in which the gainmap math is to be applied. - sk_sp<SkColorSpace> gainmapMathColorSpace = baseColorSpace->makeLinearGamma(); + sk_sp<SkColorSpace> gainmapMathColorSpace = + mGainmapInfo.fGainmapMathColorSpace + ? mGainmapInfo.fGainmapMathColorSpace->makeLinearGamma() + : baseColorSpace->makeLinearGamma(); // Create a color filter to transform from the base image's color space to the color space // in which the gainmap is to be applied. @@ -266,6 +271,10 @@ private: W = 1.f; } } + + if (mGainmapInfo.fBaseImageType == SkGainmapInfo::BaseImageType::kHDR) { + W -= 1.f; + } mBuilder.uniform("W") = W; uniforms = mBuilder.uniforms(); } @@ -317,4 +326,4 @@ sk_sp<SkShader> MakeGainmapShader(const sk_sp<const SkImage>& image, #endif // __ANDROID__ -} // namespace android::uirenderer
\ No newline at end of file +} // namespace android::uirenderer diff --git a/libs/hwui/jni/Paint.cpp b/libs/hwui/jni/Paint.cpp index da237928e5e1..a7d855d7e8ca 100644 --- a/libs/hwui/jni/Paint.cpp +++ b/libs/hwui/jni/Paint.cpp @@ -906,6 +906,13 @@ namespace PaintGlue { paint->setBlendMode(mode); } + static void setRuntimeXfermode(CRITICAL_JNI_PARAMS_COMMA jlong paintHandle, + jlong xfermodeHandle) { + Paint* paint = reinterpret_cast<Paint*>(paintHandle); + SkBlender* blender = reinterpret_cast<SkBlender*>(xfermodeHandle); + paint->setBlender(sk_ref_sp(blender)); + } + static jlong setPathEffect(CRITICAL_JNI_PARAMS_COMMA jlong objHandle, jlong effectHandle) { Paint* obj = reinterpret_cast<Paint*>(objHandle); SkPathEffect* effect = reinterpret_cast<SkPathEffect*>(effectHandle); @@ -1233,6 +1240,7 @@ static const JNINativeMethod methods[] = { {"nSetShader", "(JJ)J", (void*)PaintGlue::setShader}, {"nSetColorFilter", "(JJ)J", (void*)PaintGlue::setColorFilter}, {"nSetXfermode", "(JI)V", (void*)PaintGlue::setXfermode}, + {"nSetXfermode", "(JJ)V", (void*)PaintGlue::setRuntimeXfermode}, {"nSetPathEffect", "(JJ)J", (void*)PaintGlue::setPathEffect}, {"nSetMaskFilter", "(JJ)J", (void*)PaintGlue::setMaskFilter}, {"nSetTypeface", "(JJ)V", (void*)PaintGlue::setTypeface}, diff --git a/libs/hwui/jni/RuntimeEffectUtils.cpp b/libs/hwui/jni/RuntimeEffectUtils.cpp index 46db8633c66e..ad0e540b5b40 100644 --- a/libs/hwui/jni/RuntimeEffectUtils.cpp +++ b/libs/hwui/jni/RuntimeEffectUtils.cpp @@ -90,7 +90,7 @@ void UpdateChild(JNIEnv* env, SkRuntimeEffectBuilder* builder, const char* child SkFlattenable* childEffect) { SkRuntimeShaderBuilder::BuilderChild builderChild = builder->child(childName); if (builderChild.fChild == nullptr) { - ThrowIAEFmt(env, "unable to find shader named %s", childName); + ThrowIAEFmt(env, "unable to find child named %s", childName); return; } diff --git a/libs/hwui/jni/RuntimeXfermode.cpp b/libs/hwui/jni/RuntimeXfermode.cpp new file mode 100644 index 000000000000..c1c8964bf5eb --- /dev/null +++ b/libs/hwui/jni/RuntimeXfermode.cpp @@ -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. + */ + +#include "GraphicsJNI.h" +#include "RuntimeEffectUtils.h" +#include "SkBlender.h" + +using namespace android::uirenderer; + +static void SkRuntimeEffectBuilder_delete(SkRuntimeEffectBuilder* builder) { + delete builder; +} + +static jlong RuntimeXfermode_getNativeFinalizer(JNIEnv*, jobject) { + return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SkRuntimeEffectBuilder_delete)); +} + +static jlong RuntimeXfermode_createBuilder(JNIEnv* env, jobject, jstring sksl) { + ScopedUtfChars strSksl(env, sksl); + auto result = + SkRuntimeEffect::MakeForBlender(SkString(strSksl.c_str()), SkRuntimeEffect::Options{}); + if (result.effect.get() == nullptr) { + doThrowIAE(env, result.errorText.c_str()); + return 0; + } + return reinterpret_cast<jlong>(new SkRuntimeEffectBuilder(std::move(result.effect))); +} + +static jlong RuntimeXfermode_create(JNIEnv* env, jobject, jlong builderPtr) { + auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr); + sk_sp<SkBlender> blender = builder->makeBlender(); + if (!blender) { + doThrowIAE(env); + } + return reinterpret_cast<jlong>(blender.release()); +} + +static void RuntimeXfermode_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong builderPtr, + jstring uniformName, jfloatArray uniforms, + jboolean isColor) { + auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr); + ScopedUtfChars name(env, uniformName); + AutoJavaFloatArray autoValues(env, uniforms, 0, kRO_JNIAccess); + UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor); +} + +static void RuntimeXfermode_updateFloatUniforms(JNIEnv* env, jobject, jlong builderPtr, + jstring uniformName, jfloat value1, jfloat value2, + jfloat value3, jfloat value4, jint count) { + auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr); + ScopedUtfChars name(env, uniformName); + const float values[4] = {value1, value2, value3, value4}; + UpdateFloatUniforms(env, builder, name.c_str(), values, count, false); +} + +static void RuntimeXfermode_updateIntArrayUniforms(JNIEnv* env, jobject, jlong builderPtr, + jstring uniformName, jintArray uniforms) { + auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr); + ScopedUtfChars name(env, uniformName); + AutoJavaIntArray autoValues(env, uniforms, 0); + UpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length()); +} + +static void RuntimeXfermode_updateIntUniforms(JNIEnv* env, jobject, jlong builderPtr, + jstring uniformName, jint value1, jint value2, + jint value3, jint value4, jint count) { + auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr); + ScopedUtfChars name(env, uniformName); + const int values[4] = {value1, value2, value3, value4}; + UpdateIntUniforms(env, builder, name.c_str(), values, count); +} + +static void RuntimeXfermode_updateChild(JNIEnv* env, jobject, jlong builderPtr, jstring childName, + jlong childPtr) { + auto* builder = reinterpret_cast<SkRuntimeEffectBuilder*>(builderPtr); + ScopedUtfChars name(env, childName); + auto* child = reinterpret_cast<SkFlattenable*>(childPtr); + if (child) { + UpdateChild(env, builder, name.c_str(), child); + } +} + +static const JNINativeMethod gRuntimeXfermodeMethods[] = { + {"nativeGetFinalizer", "()J", (void*)RuntimeXfermode_getNativeFinalizer}, + {"nativeCreateBlenderBuilder", "(Ljava/lang/String;)J", + (void*)RuntimeXfermode_createBuilder}, + {"nativeCreateNativeInstance", "(J)J", (void*)RuntimeXfermode_create}, + {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V", + (void*)RuntimeXfermode_updateFloatArrayUniforms}, + {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V", + (void*)RuntimeXfermode_updateFloatUniforms}, + {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V", + (void*)RuntimeXfermode_updateIntArrayUniforms}, + {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V", + (void*)RuntimeXfermode_updateIntUniforms}, + {"nativeUpdateChild", "(JLjava/lang/String;J)V", (void*)RuntimeXfermode_updateChild}, +}; + +int register_android_graphics_RuntimeXfermode(JNIEnv* env) { + android::RegisterMethodsOrDie(env, "android/graphics/RuntimeXfermode", gRuntimeXfermodeMethods, + NELEM(gRuntimeXfermodeMethods)); + + return 0; +} diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp index 2a057e7a4cdc..018c2b1374d0 100644 --- a/libs/hwui/jni/Shader.cpp +++ b/libs/hwui/jni/Shader.cpp @@ -2,6 +2,7 @@ #include "Gainmap.h" #include "GraphicsJNI.h" +#include "RuntimeEffectUtils.h" #include "SkBitmap.h" #include "SkBlendMode.h" #include "SkColor.h" @@ -280,50 +281,6 @@ static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) { return ret; } -static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) { - switch (type) { - case SkRuntimeEffect::Uniform::Type::kFloat: - case SkRuntimeEffect::Uniform::Type::kFloat2: - case SkRuntimeEffect::Uniform::Type::kFloat3: - case SkRuntimeEffect::Uniform::Type::kFloat4: - case SkRuntimeEffect::Uniform::Type::kFloat2x2: - case SkRuntimeEffect::Uniform::Type::kFloat3x3: - case SkRuntimeEffect::Uniform::Type::kFloat4x4: - return false; - case SkRuntimeEffect::Uniform::Type::kInt: - case SkRuntimeEffect::Uniform::Type::kInt2: - case SkRuntimeEffect::Uniform::Type::kInt3: - case SkRuntimeEffect::Uniform::Type::kInt4: - return true; - } -} - -static void UpdateFloatUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, - const char* uniformName, const float values[], int count, - bool isColor) { - SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName); - if (uniform.fVar == nullptr) { - ThrowIAEFmt(env, "unable to find uniform named %s", uniformName); - } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) { - if (isColor) { - jniThrowExceptionFmt( - env, "java/lang/IllegalArgumentException", - "attempting to set a color uniform using the non-color specific APIs: %s %x", - uniformName, uniform.fVar->flags); - } else { - ThrowIAEFmt(env, - "attempting to set a non-color uniform using the setColorUniform APIs: %s", - uniformName); - } - } else if (isIntUniformType(uniform.fVar->type)) { - ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s", - uniformName); - } else if (!uniform.set<float>(values, count)) { - ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]", - uniform.fVar->sizeInBytes(), sizeof(float) * count); - } -} - static void RuntimeShader_updateFloatUniforms(JNIEnv* env, jobject, jlong shaderBuilder, jstring jUniformName, jfloat value1, jfloat value2, jfloat value3, jfloat value4, jint count) { @@ -342,20 +299,6 @@ static void RuntimeShader_updateFloatArrayUniforms(JNIEnv* env, jobject, jlong s UpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(), isColor); } -static void UpdateIntUniforms(JNIEnv* env, SkRuntimeShaderBuilder* builder, const char* uniformName, - const int values[], int count) { - SkRuntimeShaderBuilder::BuilderUniform uniform = builder->uniform(uniformName); - if (uniform.fVar == nullptr) { - ThrowIAEFmt(env, "unable to find uniform named %s", uniformName); - } else if (!isIntUniformType(uniform.fVar->type)) { - ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s", - uniformName); - } else if (!uniform.set<int>(values, count)) { - ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]", - uniform.fVar->sizeInBytes(), sizeof(float) * count); - } -} - static void RuntimeShader_updateIntUniforms(JNIEnv* env, jobject, jlong shaderBuilder, jstring jUniformName, jint value1, jint value2, jint value3, jint value4, jint count) { @@ -388,6 +331,15 @@ static void RuntimeShader_updateShader(JNIEnv* env, jobject, jlong shaderBuilder builder->child(name.c_str()) = sk_ref_sp(shader); } +static void RuntimeShader_updateChild(JNIEnv* env, jobject, jlong shaderBuilder, + jstring jUniformName, jlong childHandle) { + SkRuntimeShaderBuilder* builder = reinterpret_cast<SkRuntimeShaderBuilder*>(shaderBuilder); + ScopedUtfChars name(env, jUniformName); + auto* childEffect = reinterpret_cast<SkFlattenable*>(childHandle); + + UpdateChild(env, builder, name.c_str(), childEffect); +} + /////////////////////////////////////////////////////////////////////////////////////////////// static const JNINativeMethod gShaderMethods[] = { @@ -428,6 +380,7 @@ static const JNINativeMethod gRuntimeShaderMethods[] = { {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V", (void*)RuntimeShader_updateIntUniforms}, {"nativeUpdateShader", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateShader}, + {"nativeUpdateChild", "(JLjava/lang/String;J)V", (void*)RuntimeShader_updateChild}, }; int register_android_graphics_Shader(JNIEnv* env) diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java index 2da8eecedc4d..b41f40f412d2 100644 --- a/media/java/android/media/AudioDeviceInfo.java +++ b/media/java/android/media/AudioDeviceInfo.java @@ -17,6 +17,7 @@ package android.media; import static android.media.audio.Flags.FLAG_ENABLE_MULTICHANNEL_GROUP_DEVICE; +import static android.media.audio.Flags.FLAG_SPEAKER_LAYOUT_API; import android.Manifest; import android.annotation.FlaggedApi; @@ -548,6 +549,19 @@ public final class AudioDeviceInfo { } /** + * @return A ChannelMask representing the physical output speaker layout of the device. + * + * The layout channel mask only indicates which speaker channels are present, the + * physical layout of the speakers should be informed by a standard for multi-channel + * sound playback systems, such as ITU-R BS.2051. + * @see AudioFormat + */ + @FlaggedApi(FLAG_SPEAKER_LAYOUT_API) + public int getSpeakerLayoutChannelMask() { + return mPort.speakerLayoutChannelMask(); + } + + /** * @return An array of audio encodings (e.g. {@link AudioFormat#ENCODING_PCM_16BIT}, * {@link AudioFormat#ENCODING_PCM_FLOAT}) supported by the audio device. * <code>ENCODING_PCM_FLOAT</code> indicates the device supports more diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java index ab5c54b5cd7e..f5913c763b82 100644 --- a/media/java/android/media/AudioDevicePort.java +++ b/media/java/android/media/AudioDevicePort.java @@ -60,8 +60,27 @@ public class AudioDevicePort extends AudioPort { /* encapsulationMetadataTypes= */ null); } + /** @hide */ + // TODO: b/316864909 - Remove this method once there's a way to fake audio device ports further + // down the stack. + @VisibleForTesting + public static AudioDevicePort createForTesting(int speakerLayoutChannelMask) { + return new AudioDevicePort( + new AudioHandle(/* id= */ 0), + /* name= */ "testAudioDevicePort", + /* profiles= */ null, + /* gains= */ null, + /* type= */ AudioManager.DEVICE_OUT_SPEAKER, + /* address= */ "testAddress", + /* speakerLayoutChannelMask= */ speakerLayoutChannelMask, + /* encapsulationModes= */ null, + /* encapsulationMetadataTypes= */ null, + /* descriptors= */ null); + } + private final int mType; private final String mAddress; + private final int mSpeakerLayoutChannelMask; private final int[] mEncapsulationModes; private final int[] mEncapsulationMetadataTypes; @@ -76,12 +95,20 @@ public class AudioDevicePort extends AudioPort { deviceName, samplingRates, channelMasks, channelIndexMasks, formats, gains); mType = type; mAddress = address; + mSpeakerLayoutChannelMask = AudioFormat.CHANNEL_INVALID; mEncapsulationModes = encapsulationModes; mEncapsulationMetadataTypes = encapsulationMetadataTypes; } - AudioDevicePort(AudioHandle handle, String deviceName, List<AudioProfile> profiles, - AudioGain[] gains, int type, String address, int[] encapsulationModes, + AudioDevicePort( + AudioHandle handle, + String deviceName, + List<AudioProfile> profiles, + AudioGain[] gains, + int type, + String address, + int speakerLayoutChannelMask, + int[] encapsulationModes, @AudioTrack.EncapsulationMetadataType int[] encapsulationMetadataTypes, List<AudioDescriptor> descriptors) { super(handle, @@ -89,6 +116,7 @@ public class AudioDevicePort extends AudioPort { deviceName, profiles, gains, descriptors); mType = type; mAddress = address; + mSpeakerLayoutChannelMask = speakerLayoutChannelMask; mEncapsulationModes = encapsulationModes; mEncapsulationMetadataTypes = encapsulationMetadataTypes; } @@ -119,6 +147,16 @@ public class AudioDevicePort extends AudioPort { return mAddress; } + /** Get the channel mask representing the physical output speaker layout of the device. + * + * The layout channel mask only indicates which speaker channels are present, the + * physical layout of the speakers should be informed by a standard for multi-channel + * sound playback systems, such as ITU-R BS.2051. + */ + public int speakerLayoutChannelMask() { + return mSpeakerLayoutChannelMask; + } + /** * Get supported encapsulation modes. */ diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java index 3cd5f5266ef2..c085b8985783 100644 --- a/media/java/android/media/AudioPlaybackConfiguration.java +++ b/media/java/android/media/AudioPlaybackConfiguration.java @@ -19,6 +19,7 @@ package android.media; import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_ALL; import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_NONE; import static android.media.audio.Flags.FLAG_MUTED_BY_PORT_VOLUME_API; +import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS; import android.annotation.FlaggedApi; import android.annotation.IntDef; @@ -39,6 +40,9 @@ import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Objects; /** @@ -56,6 +60,8 @@ public final class AudioPlaybackConfiguration implements Parcelable { public static final int PLAYER_UPID_INVALID = -1; /** @hide */ public static final int PLAYER_DEVICEID_INVALID = 0; + /** @hide */ + public static final int[] PLAYER_DEVICEIDS_INVALID = new int[0]; // information about the implementation /** @@ -332,7 +338,7 @@ public final class AudioPlaybackConfiguration implements Parcelable { private final Object mUpdateablePropLock = new Object(); @GuardedBy("mUpdateablePropLock") - private int mDeviceId; + private @NonNull int[] mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID; @GuardedBy("mUpdateablePropLock") private int mSessionId; @GuardedBy("mUpdateablePropLock") @@ -361,7 +367,7 @@ public final class AudioPlaybackConfiguration implements Parcelable { mClientUid = uid; mClientPid = pid; mMutedState = 0; - mDeviceId = PLAYER_DEVICEID_INVALID; + mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID; mPlayerState = PLAYER_STATE_IDLE; mPlayerAttr = pic.mAttributes; if ((sPlayerDeathMonitor != null) && (pic.mIPlayer != null)) { @@ -385,10 +391,11 @@ public final class AudioPlaybackConfiguration implements Parcelable { } // sets the fields that are updateable and require synchronization - private void setUpdateableFields(int deviceId, int sessionId, int mutedState, FormatInfo format) + private void setUpdateableFields(int[] deviceIds, int sessionId, int mutedState, + FormatInfo format) { synchronized (mUpdateablePropLock) { - mDeviceId = deviceId; + mDeviceIds = deviceIds; mSessionId = sessionId; mMutedState = mutedState; mFormatInfo = format; @@ -424,7 +431,7 @@ public final class AudioPlaybackConfiguration implements Parcelable { anonymCopy.mClientPid = PLAYER_UPID_INVALID; anonymCopy.mIPlayerShell = null; anonymCopy.setUpdateableFields( - /*deviceId*/ PLAYER_DEVICEID_INVALID, + /*deviceIds*/ new int[0], /*sessionId*/ AudioSystem.AUDIO_SESSION_ALLOCATE, /*mutedState*/ 0, FormatInfo.DEFAULT); @@ -461,17 +468,46 @@ public final class AudioPlaybackConfiguration implements Parcelable { /** * Returns information about the {@link AudioDeviceInfo} used for this playback. - * @return the audio playback device or null if the device is not available at the time of query + * @return the audio playback device or null if the device is not available at the time of + * query. + * @deprecated this information was never populated */ + @Deprecated + @FlaggedApi(FLAG_ROUTED_DEVICE_IDS) public @Nullable AudioDeviceInfo getAudioDeviceInfo() { - final int deviceId; + final int[] deviceIds; synchronized (mUpdateablePropLock) { - deviceId = mDeviceId; + deviceIds = mDeviceIds; } - if (deviceId == PLAYER_DEVICEID_INVALID) { + if (deviceIds.length == 0) { return null; } - return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS); + return AudioManager.getDeviceForPortId(deviceIds[0], AudioManager.GET_DEVICES_OUTPUTS); + } + + /** + * @hide + * Returns information about the List of {@link AudioDeviceInfo} used for this playback. + * @return the audio playback devices + */ + @SystemApi + @FlaggedApi(FLAG_ROUTED_DEVICE_IDS) + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public @NonNull List<AudioDeviceInfo> getAudioDeviceInfos() { + List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>(); + final int[] deviceIds; + synchronized (mUpdateablePropLock) { + deviceIds = mDeviceIds; + } + + for (int i = 0; i < deviceIds.length; i++) { + AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i], + AudioManager.GET_DEVICES_OUTPUTS); + if (audioDeviceInfo != null) { + audioDeviceInfos.add(audioDeviceInfo); + } + } + return audioDeviceInfos; } /** @@ -677,15 +713,15 @@ public final class AudioPlaybackConfiguration implements Parcelable { * @hide * Handle a player state change * @param event - * @param deviceId active device id or {@Code PLAYER_DEVICEID_INVALID} - * <br>Note device id is valid for {@code PLAYER_UPDATE_DEVICE_ID} or - * <br>{@code PLAYER_STATE_STARTED} events, as the device id will be reset to none when - * <br>pausing or stopping playback. It will be set to active device when playback starts or + * @param deviceIds an array of device ids. This can be empty. + * <br>Note device ids are non-empty for {@code PLAYER_UPDATE_DEVICE_ID} or + * <br>{@code PLAYER_STATE_STARTED} events, as the device ids will be emptied when pausing + * <br>or stopping playback. It will be set to active devices when playback starts or * <br>it will be changed when PLAYER_UPDATE_DEVICE_ID is sent. The latter can happen if the - * <br>device changes in the middle of playback. + * <br>devices change in the middle of playback. * @return true if the state changed, false otherwise */ - public boolean handleStateEvent(int event, int deviceId) { + public boolean handleStateEvent(int event, int[] deviceIds) { boolean changed = false; synchronized (mUpdateablePropLock) { @@ -696,8 +732,8 @@ public final class AudioPlaybackConfiguration implements Parcelable { } if (event == PLAYER_STATE_STARTED || event == PLAYER_UPDATE_DEVICE_ID) { - changed = changed || (mDeviceId != deviceId); - mDeviceId = deviceId; + changed = changed || !Arrays.equals(mDeviceIds, deviceIds); + mDeviceIds = deviceIds; } if (changed && (event == PLAYER_STATE_RELEASED) && (mIPlayerShell != null)) { @@ -777,8 +813,8 @@ public final class AudioPlaybackConfiguration implements Parcelable { @Override public int hashCode() { synchronized (mUpdateablePropLock) { - return Objects.hash(mPlayerIId, mDeviceId, mMutedState, mPlayerType, mClientUid, - mClientPid, mSessionId); + return Objects.hash(mPlayerIId, Arrays.toString(mDeviceIds), mMutedState, mPlayerType, + mClientUid, mClientPid, mSessionId); } } @@ -791,7 +827,7 @@ public final class AudioPlaybackConfiguration implements Parcelable { public void writeToParcel(Parcel dest, int flags) { synchronized (mUpdateablePropLock) { dest.writeInt(mPlayerIId); - dest.writeInt(mDeviceId); + dest.writeIntArray(mDeviceIds); dest.writeInt(mMutedState); dest.writeInt(mPlayerType); dest.writeInt(mClientUid); @@ -810,7 +846,10 @@ public final class AudioPlaybackConfiguration implements Parcelable { private AudioPlaybackConfiguration(Parcel in) { mPlayerIId = in.readInt(); - mDeviceId = in.readInt(); + mDeviceIds = new int[in.readInt()]; + for (int i = 0; i < mDeviceIds.length; i++) { + mDeviceIds[i] = in.readInt(); + } mMutedState = in.readInt(); mPlayerType = in.readInt(); mClientUid = in.readInt(); @@ -831,7 +870,7 @@ public final class AudioPlaybackConfiguration implements Parcelable { AudioPlaybackConfiguration that = (AudioPlaybackConfiguration) o; return ((mPlayerIId == that.mPlayerIId) - && (mDeviceId == that.mDeviceId) + && Arrays.equals(mDeviceIds, that.mDeviceIds) && (mMutedState == that.mMutedState) && (mPlayerType == that.mPlayerType) && (mClientUid == that.mClientUid) @@ -844,7 +883,7 @@ public final class AudioPlaybackConfiguration implements Parcelable { StringBuilder apcToString = new StringBuilder(); synchronized (mUpdateablePropLock) { apcToString.append("AudioPlaybackConfiguration piid:").append(mPlayerIId).append( - " deviceId:").append(mDeviceId).append(" type:").append( + " deviceIds:").append(Arrays.toString(mDeviceIds)).append(" type:").append( toLogFriendlyPlayerType(mPlayerType)).append(" u/pid:").append( mClientUid).append( "/").append(mClientPid).append(" state:").append( diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 80e57193d0dc..cacd59f42ec4 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -20,8 +20,10 @@ import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAUL import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE; +import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; @@ -1906,17 +1908,49 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, } /** + * Internal API of getRoutedDevices(). We should not call flag APIs internally. + */ + private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() { + List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>(); + final int[] deviceIds = native_getRoutedDeviceIds(); + if (deviceIds == null || deviceIds.length == 0) { + return audioDeviceInfos; + } + + for (int i = 0; i < deviceIds.length; i++) { + AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i], + AudioManager.GET_DEVICES_INPUTS); + if (audioDeviceInfo != null) { + audioDeviceInfos.add(audioDeviceInfo); + } + } + return audioDeviceInfos; + } + + /** * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioRecord. * Note: The query is only valid if the AudioRecord is currently recording. If it is not, * <code>getRoutedDevice()</code> will return null. */ @Override public AudioDeviceInfo getRoutedDevice() { - int deviceId = native_getRoutedDeviceId(); - if (deviceId == 0) { + final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal(); + if (audioDeviceInfos.isEmpty()) { return null; } - return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS); + return audioDeviceInfos.get(0); + } + + /** + * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this + * AudioRecord. + * Note: The query is only valid if the AudioRecord is currently playing. If it is not, + * <code>getRoutedDevices()</code> will return an empty list. + */ + @Override + @FlaggedApi(FLAG_ROUTED_DEVICE_IDS) + public @NonNull List<AudioDeviceInfo> getRoutedDevices() { + return getRoutedDevicesInternal(); } /** @@ -2494,7 +2528,7 @@ public class AudioRecord implements AudioRouting, MicrophoneDirection, int sampleRateInHz, int channelCount, int audioFormat); private native final boolean native_setInputDevice(int deviceId); - private native final int native_getRoutedDeviceId(); + private native int[] native_getRoutedDeviceIds(); private native final void native_enableDeviceCallback(); private native final void native_disableDeviceCallback(); diff --git a/media/java/android/media/AudioRouting.java b/media/java/android/media/AudioRouting.java index 26fa631ac6ac..22aa9a09d560 100644 --- a/media/java/android/media/AudioRouting.java +++ b/media/java/android/media/AudioRouting.java @@ -16,9 +16,16 @@ package android.media; +import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS; + +import android.annotation.FlaggedApi; +import android.annotation.NonNull; import android.os.Handler; import android.os.Looper; +import java.util.ArrayList; +import java.util.List; + /** * AudioRouting defines an interface for controlling routing and routing notifications in * AudioTrack and AudioRecord objects. @@ -49,6 +56,22 @@ public interface AudioRouting { public AudioDeviceInfo getRoutedDevice(); /** + * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this + * AudioTrack/AudioRecord. + * Note: The query is only valid if the AudioTrack/AudioRecord is currently playing. + * If it is not, <code>getRoutedDevices()</code> will return an empty List. + */ + @FlaggedApi(FLAG_ROUTED_DEVICE_IDS) + default @NonNull List<AudioDeviceInfo> getRoutedDevices() { + List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>(); + AudioDeviceInfo audioDeviceInfo = getRoutedDevice(); + if (audioDeviceInfo != null) { + audioDeviceInfos.add(audioDeviceInfo); + } + return new ArrayList<AudioDeviceInfo>(); + } + + /** * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing * changes on this AudioTrack/AudioRecord. * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index 03cd53580b1b..a5d9adb5cadc 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -17,8 +17,10 @@ package android.media; import static android.media.AudioManager.AUDIO_SESSION_ID_GENERATE; +import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS; import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; @@ -54,7 +56,9 @@ import java.lang.ref.WeakReference; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.NioUtils; +import java.util.ArrayList; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.Executor; @@ -3019,7 +3023,7 @@ public class AudioTrack extends PlayerBase } } synchronized(mPlayStateLock) { - baseStart(0); // unknown device at this point + baseStart(new int[0]); // unknown device at this point native_start(); // FIXME see b/179218630 //baseStart(native_getRoutedDeviceId()); @@ -3780,17 +3784,51 @@ public class AudioTrack extends PlayerBase } /** + * Internal API of getRoutedDevices(). We should not call flag APIs internally. + */ + private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() { + List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>(); + final int[] deviceIds = native_getRoutedDeviceIds(); + if (deviceIds == null || deviceIds.length == 0) { + return audioDeviceInfos; + } + + for (int i = 0; i < deviceIds.length; i++) { + AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i], + AudioManager.GET_DEVICES_OUTPUTS); + if (audioDeviceInfo != null) { + audioDeviceInfos.add(audioDeviceInfo); + } + } + return audioDeviceInfos; + } + + /** * Returns an {@link AudioDeviceInfo} identifying the current routing of this AudioTrack. * Note: The query is only valid if the AudioTrack is currently playing. If it is not, * <code>getRoutedDevice()</code> will return null. + * Audio may play on multiple devices simultaneously (e.g. an alarm playing on headphones and + * speaker on a phone), so prefer using {@link #getRoutedDevices}. */ @Override public AudioDeviceInfo getRoutedDevice() { - int deviceId = native_getRoutedDeviceId(); - if (deviceId == 0) { + final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal(); + if (audioDeviceInfos.isEmpty()) { return null; } - return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS); + return audioDeviceInfos.get(0); + } + + /** + * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this + * AudioTrack. + * Note: The query is only valid if the AudioTrack is currently playing. If it is not, + * <code>getRoutedDevices()</code> will return an empty list. + */ + @Override + @FlaggedApi(FLAG_ROUTED_DEVICE_IDS) + public @NonNull List<AudioDeviceInfo> getRoutedDevices() { + return getRoutedDevicesInternal(); } private void tryToDisableNativeRoutingCallback() { @@ -3950,7 +3988,7 @@ public class AudioTrack extends PlayerBase */ private void broadcastRoutingChange() { AudioManager.resetAudioPortGeneration(); - baseUpdateDeviceId(getRoutedDevice()); + baseUpdateDeviceIds(getRoutedDevicesInternal()); synchronized (mRoutingChangeListeners) { for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) { delegate.notifyClient(); @@ -4507,7 +4545,7 @@ public class AudioTrack extends PlayerBase private native final int native_setAuxEffectSendLevel(float level); private native final boolean native_setOutputDevice(int deviceId); - private native final int native_getRoutedDeviceId(); + private native int[] native_getRoutedDeviceIds(); private native final void native_enableDeviceCallback(); private native final void native_disableDeviceCallback(); diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java index 167ab6535843..68a3aa7eb834 100644 --- a/media/java/android/media/HwAudioSource.java +++ b/media/java/android/media/HwAudioSource.java @@ -145,7 +145,14 @@ public class HwAudioSource extends PlayerBase { mAudioAttributes); if (isPlaying()) { // FIXME: b/174876389 clean up device id reporting - baseStart(getDeviceId()); + // Set as deviceIds empty and create an array with element if device id is valid. + int[] deviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID; + int deviceId = getDeviceId(); + if (deviceId != 0) { + deviceIds = new int[1]; + deviceIds[0] = deviceId; + } + baseStart(deviceIds); } } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 9fd3f5beb25c..08b0dd3fb11c 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -87,7 +87,7 @@ interface IAudioService { oneway void playerAttributes(in int piid, in AudioAttributes attr); - oneway void playerEvent(in int piid, in int event, in int eventId); + oneway void playerEvent(in int piid, in int event, in int[] eventId); oneway void releasePlayer(in int piid); diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java index 93259992d339..0a79f41e1ff0 100644 --- a/media/java/android/media/ImageWriter.java +++ b/media/java/android/media/ImageWriter.java @@ -1157,7 +1157,11 @@ public class ImageWriter implements AutoCloseable { @Override public void setFence(@NonNull SyncFence fence) throws IOException { throwISEIfImageIsInvalid(); - nativeSetFenceFd(fence.getFdDup().detachFd()); + if (fence.isValid()) { + nativeSetFenceFd(fence.getFdDup().detachFd()); + } else { + nativeSetFenceFd(-1); + } } @Override diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java index 3f9126aa9456..1ecba31ce07f 100644 --- a/media/java/android/media/MediaCas.java +++ b/media/java/android/media/MediaCas.java @@ -16,10 +16,9 @@ package android.media; +import static android.media.tv.flags.Flags.FLAG_MEDIACAS_UPDATE_CLIENT_PROFILE_PRIORITY; import static android.media.tv.flags.Flags.FLAG_SET_RESOURCE_HOLDER_RETAIN; -import static com.android.media.flags.Flags.FLAG_UPDATE_CLIENT_PROFILE_PRIORITY; - import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; @@ -996,7 +995,7 @@ public final class MediaCas implements AutoCloseable { * @param niceValue the nice value. * @hide */ - @FlaggedApi(FLAG_UPDATE_CLIENT_PROFILE_PRIORITY) + @FlaggedApi(FLAG_MEDIACAS_UPDATE_CLIENT_PROFILE_PRIORITY) @SystemApi @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS) public boolean updateResourcePriority(int priority, int niceValue) { diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index a0f8ae5defeb..f1c2a7aec903 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -18,7 +18,9 @@ package android.media; import static android.Manifest.permission.BIND_IMS_SERVICE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -84,6 +86,7 @@ import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.net.URL; import java.nio.ByteOrder; +import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.HashMap; @@ -1412,7 +1415,7 @@ public class MediaPlayer extends PlayerBase } private void startImpl() { - baseStart(0); // unknown device at this point + baseStart(new int[0]); // unknown device at this point stayAwake(true); tryToEnableNativeRoutingCallback(); _start(); @@ -1538,20 +1541,54 @@ public class MediaPlayer extends PlayerBase } /** + * Internal API of getRoutedDevices(). We should not call flag APIs internally. + */ + private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() { + List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>(); + final int[] deviceIds = native_getRoutedDeviceIds(); + if (deviceIds == null || deviceIds.length == 0) { + return audioDeviceInfos; + } + + for (int i = 0; i < deviceIds.length; i++) { + AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i], + AudioManager.GET_DEVICES_OUTPUTS); + if (audioDeviceInfo != null) { + audioDeviceInfos.add(audioDeviceInfo); + } + } + return audioDeviceInfos; + } + + /** * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer * Note: The query is only valid if the MediaPlayer is currently playing. * If the player is not playing, the returned device can be null or correspond to previously * selected device when the player was last active. + * Audio may play on multiple devices simultaneously (e.g. an alarm playing on headphones and + * speaker on a phone), so prefer using {@link #getRoutedDevices}. */ @Override public AudioDeviceInfo getRoutedDevice() { - int deviceId = native_getRoutedDeviceId(); - if (deviceId == 0) { + final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal(); + if (audioDeviceInfos.isEmpty()) { return null; } - return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_OUTPUTS); + return audioDeviceInfos.get(0); } + /** + * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this + * MediaPlayer. + * Note: The query is only valid if the MediaPlayer is currently playing. + * If the player is not playing, the returned devices can be empty or correspond to previously + * selected devices when the player was last active. + */ + @Override + @FlaggedApi(FLAG_ROUTED_DEVICE_IDS) + public @NonNull List<AudioDeviceInfo> getRoutedDevices() { + return getRoutedDevicesInternal(); + } /** * Sends device list change notification to all listeners. @@ -1562,7 +1599,7 @@ public class MediaPlayer extends PlayerBase // Prevent the case where an event is triggered by registering a routing change // listener via the media player. if (mEnableSelfRoutingMonitor) { - baseUpdateDeviceId(getRoutedDevice()); + baseUpdateDeviceIds(getRoutedDevicesInternal()); } for (NativeRoutingEventHandlerDelegate delegate : mRoutingChangeListeners.values()) { @@ -1672,7 +1709,7 @@ public class MediaPlayer extends PlayerBase } private native final boolean native_setOutputDevice(int deviceId); - private native final int native_getRoutedDeviceId(); + private native int[] native_getRoutedDeviceIds(); private native final void native_enableDeviceCallback(boolean enabled); /** diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index 2d17bf500f12..7af78b81cda5 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -16,7 +16,10 @@ package android.media; +import static android.media.audio.Flags.FLAG_ROUTED_DEVICE_IDS; + import android.annotation.CallbackExecutor; +import android.annotation.FlaggedApi; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.NonNull; @@ -1681,6 +1684,26 @@ public class MediaRecorder implements AudioRouting, } /** + * Internal API of getRoutedDevices(). We should not call flag APIs internally. + */ + private @NonNull List<AudioDeviceInfo> getRoutedDevicesInternal() { + List<AudioDeviceInfo> audioDeviceInfos = new ArrayList<AudioDeviceInfo>(); + final int[] deviceIds = native_getRoutedDeviceIds(); + if (deviceIds == null || deviceIds.length == 0) { + return audioDeviceInfos; + } + + for (int i = 0; i < deviceIds.length; i++) { + AudioDeviceInfo audioDeviceInfo = AudioManager.getDeviceForPortId(deviceIds[i], + AudioManager.GET_DEVICES_INPUTS); + if (audioDeviceInfo != null) { + audioDeviceInfos.add(audioDeviceInfo); + } + } + return audioDeviceInfos; + } + + /** * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaRecorder * Note: The query is only valid if the MediaRecorder is currently recording. * If the recorder is not recording, the returned device can be null or correspond to previously @@ -1688,11 +1711,24 @@ public class MediaRecorder implements AudioRouting, */ @Override public AudioDeviceInfo getRoutedDevice() { - int deviceId = native_getRoutedDeviceId(); - if (deviceId == 0) { + final List<AudioDeviceInfo> audioDeviceInfos = getRoutedDevicesInternal(); + if (audioDeviceInfos.isEmpty()) { return null; } - return AudioManager.getDeviceForPortId(deviceId, AudioManager.GET_DEVICES_INPUTS); + return audioDeviceInfos.get(0); + } + + /** + * Returns a List of {@link AudioDeviceInfo} identifying the current routing of this + * MediaRecorder. + * Note: The query is only valid if the MediaRecorder is currently recording. + * If the recorder is not recording, the returned devices can be empty or correspond to + * previously selected devices when the recorder was last active. + */ + @Override + @FlaggedApi(FLAG_ROUTED_DEVICE_IDS) + public @NonNull List<AudioDeviceInfo> getRoutedDevices() { + return getRoutedDevicesInternal(); } /* @@ -1752,7 +1788,7 @@ public class MediaRecorder implements AudioRouting, } private native final boolean native_setInputDevice(int deviceId); - private native final int native_getRoutedDeviceId(); + private native int[] native_getRoutedDeviceIds(); private native final void native_enableDeviceCallback(boolean enabled); //-------------------------------------------------------------------------- diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java index 3f44b09124e4..dbf8338ac99f 100644 --- a/media/java/android/media/PlayerBase.java +++ b/media/java/android/media/PlayerBase.java @@ -39,6 +39,8 @@ import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; import java.lang.ref.WeakReference; +import java.util.Arrays; +import java.util.List; import java.util.Objects; /** @@ -91,7 +93,7 @@ public abstract class PlayerBase { @GuardedBy("mLock") private float mVolMultiplier = 1.0f; @GuardedBy("mLock") - private int mDeviceId; + private @NonNull int[] mDeviceIds = AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID; /** * Constructor. Must be given audio attributes, as they are required for AppOps. @@ -158,35 +160,36 @@ public abstract class PlayerBase { } } - void baseUpdateDeviceId(@Nullable AudioDeviceInfo deviceInfo) { - int deviceId = 0; - if (deviceInfo != null) { - deviceId = deviceInfo.getId(); + void baseUpdateDeviceIds(@NonNull List<AudioDeviceInfo> deviceInfos) { + int[] deviceIds = new int[deviceInfos.size()]; + for (int i = 0; i < deviceInfos.size(); i++) { + deviceIds[i] = deviceInfos.get(i).getId(); } + int piid; synchronized (mLock) { piid = mPlayerIId; - mDeviceId = deviceId; + mDeviceIds = deviceIds; } try { getService().playerEvent(piid, - AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceId); + AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID, deviceIds); } catch (RemoteException e) { Log.e(TAG, "Error talking to audio service, " - + deviceId + + Arrays.toString(deviceIds) + " device id will not be tracked for piid=" + piid, e); } } - private void updateState(int state, int deviceId) { + private void updateState(int state, @NonNull int[] deviceIds) { final int piid; synchronized (mLock) { mState = state; piid = mPlayerIId; - mDeviceId = deviceId; + mDeviceIds = deviceIds; } try { - getService().playerEvent(piid, state, deviceId); + getService().playerEvent(piid, state, deviceIds); } catch (RemoteException e) { Log.e(TAG, "Error talking to audio service, " + AudioPlaybackConfiguration.toLogFriendlyPlayerState(state) @@ -194,11 +197,12 @@ public abstract class PlayerBase { } } - void baseStart(int deviceId) { + void baseStart(@NonNull int[] deviceIds) { if (DEBUG) { - Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId=" + deviceId); + Log.v(TAG, "baseStart() piid=" + mPlayerIId + " deviceId=" + + Arrays.toString(deviceIds)); } - updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceId); + updateState(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, deviceIds); } void baseSetStartDelayMs(int delayMs) { @@ -215,12 +219,12 @@ public abstract class PlayerBase { void basePause() { if (DEBUG) { Log.v(TAG, "basePause() piid=" + mPlayerIId); } - updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, 0); + updateState(AudioPlaybackConfiguration.PLAYER_STATE_PAUSED, new int[0]); } void baseStop() { if (DEBUG) { Log.v(TAG, "baseStop() piid=" + mPlayerIId); } - updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, 0); + updateState(AudioPlaybackConfiguration.PLAYER_STATE_STOPPED, new int[0]); } void baseSetPan(float pan) { diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java index 7b9ff23596d9..f22cc9c08b4c 100644 --- a/media/java/android/media/SoundPool.java +++ b/media/java/android/media/SoundPool.java @@ -317,7 +317,7 @@ public class SoundPool extends PlayerBase { // FIXME: b/174876164 implement device id for soundpool try { Trace.traceBegin(Trace.TRACE_TAG_AUDIO, "SoundPool.play"); - baseStart(0); + baseStart(new int[0]); return _play(soundID, leftVolume, rightVolume, priority, loop, rate, getPlayerIId()); } finally { Trace.traceEnd(Trace.TRACE_TAG_AUDIO); diff --git a/media/java/android/media/flags/media_better_together.aconfig b/media/java/android/media/flags/media_better_together.aconfig index 7895eb27b372..d8a8c8b0ee2a 100644 --- a/media/java/android/media/flags/media_better_together.aconfig +++ b/media/java/android/media/flags/media_better_together.aconfig @@ -1,13 +1,7 @@ package: "com.android.media.flags" container: "system" -flag { - name: "enable_rlp_callbacks_in_media_router2" - is_exported: true - namespace: "media_solutions" - description: "Make RouteListingPreference getter and callbacks public in MediaRouter2." - bug: "281067101" -} +# Flags are ordered alphabetically by name. flag { name: "adjust_volume_for_foreground_app_playing_audio_without_media_session" @@ -17,6 +11,13 @@ flag { } flag { + name: "enable_audio_input_device_routing_and_volume_control" + namespace: "media_better_together" + description: "Allows audio input devices routing and volume control via system settings." + bug: "355684672" +} + +flag { name: "enable_audio_policies_device_and_bluetooth_controller" is_exported: true namespace: "media_solutions" @@ -25,71 +26,70 @@ flag { } flag { - name: "fallback_to_default_handling_when_media_session_has_fixed_volume_handling" - namespace: "media_solutions" - description: "Fallbacks to the default handling for volume adjustment when media session has fixed volume handling and its app is in the foreground and setting a media controller." - bug: "293743975" -} - -flag { - name: "enable_waiting_state_for_system_session_creation_request" - namespace: "media_solutions" - description: "Introduces a waiting state for the session creation request and prevents it from early failing when the selectedRoute from the bluetooth stack doesn't match the pending request route id." - bug: "307723189" + name: "enable_built_in_speaker_route_suitability_statuses" + is_exported: true + namespace: "media_solutions" + description: "Make MediaRoute2Info provide information about routes suitability for transfer." + bug: "279555229" } flag { - name: "enable_new_media_route_2_info_types" + name: "enable_cross_user_routing_in_media_router2" is_exported: true namespace: "media_solutions" - description: "Enables the following type constants in MediaRoute2Info: CAR, COMPUTER, GAME_CONSOLE, SMARTPHONE, SMARTWATCH, TABLET, TABLET_DOCKED. Note that this doesn't gate any behavior. It only guards some API int symbols." - bug: "301713440" + description: "Allows clients of privileged MediaRouter2 that hold INTERACT_ACROSS_USERS_FULL to control routing across users." + bug: "288580225" } flag { - name: "enable_new_wired_media_route_2_info_types" - is_exported: true - namespace: "media_tv" - description: "Enables the following type constant in MediaRoute2Info: LINE_ANALOG, LINE_DIGITAL, AUX_LINE" - bug: "375691732" + name: "enable_full_scan_with_media_content_control" + namespace: "media_better_together" + description: "Allows holders of the MEDIA_CONTENT_CONTROL permission to scan for routes while not in the foreground." + bug: "352401364" + metadata { + purpose: PURPOSE_BUGFIX + } } flag { - name: "enable_privileged_routing_for_media_routing_control" + name: "enable_get_transferable_routes" is_exported: true namespace: "media_solutions" - description: "Allow access to privileged routing capabilities to MEDIA_ROUTING_CONTROL holders." - bug: "305919655" + description: "Exposes RoutingController#getTransferableRoutes() (previously hidden) to the public API." + bug: "323154573" } flag { - name: "enable_cross_user_routing_in_media_router2" - is_exported: true - namespace: "media_solutions" - description: "Allows clients of privileged MediaRouter2 that hold INTERACT_ACROSS_USERS_FULL to control routing across users." - bug: "288580225" + name: "enable_mirroring_in_media_router_2" + namespace: "media_better_together" + description: "Enables support for mirroring routes in the MediaRouter2 framework, allowing Output Switcher to offer mirroring routes." + bug: "362507305" } flag { - name: "enable_use_of_bluetooth_device_get_alias_for_mr2info_get_name" + name: "enable_mr2_service_non_main_bg_thread" namespace: "media_solutions" - description: "Use BluetoothDevice.getAlias to populate the name of Bluetooth MediaRoute2Infos." - bug: "314324170" + description: "Enables the use of a background thread in the media routing framework, instead of using the main thread." + bug: "310145678" + metadata { + purpose: PURPOSE_BUGFIX + } } flag { - name: "update_client_profile_priority" + name: "enable_new_media_route_2_info_types" + is_exported: true namespace: "media_solutions" - description : "Feature flag to add updateResourcePriority api to MediaCas" - bug: "300565729" + description: "Enables the following type constants in MediaRoute2Info: CAR, COMPUTER, GAME_CONSOLE, SMARTPHONE, SMARTWATCH, TABLET, TABLET_DOCKED. Note that this doesn't gate any behavior. It only guards some API int symbols." + bug: "301713440" } flag { - name: "enable_built_in_speaker_route_suitability_statuses" - is_exported: true - namespace: "media_solutions" - description: "Make MediaRoute2Info provide information about routes suitability for transfer." - bug: "279555229" + name: "enable_new_wired_media_route_2_info_types" + is_exported: true + namespace: "media_tv" + description: "Enables the following type constant in MediaRoute2Info: LINE_ANALOG, LINE_DIGITAL, AUX_LINE" + bug: "375691732" } flag { @@ -101,11 +101,10 @@ flag { } flag { - name: "enable_get_transferable_routes" - is_exported: true + name: "enable_null_session_in_media_browser_service" namespace: "media_solutions" - description: "Exposes RoutingController#getTransferableRoutes() (previously hidden) to the public API." - bug: "323154573" + description: "Enables apps owning a MediaBrowserService to disconnect all connected browsers." + bug: "185136506" } flag { @@ -116,60 +115,56 @@ flag { } flag { - name: "enable_mr2_service_non_main_bg_thread" + name: "enable_prevention_of_manager_scans_when_no_apps_scan" namespace: "media_solutions" - description: "Enables the use of a background thread in the media routing framework, instead of using the main thread." - bug: "310145678" + description: "Prevents waking up route providers when no apps are scanning, even if SysUI or Settings are scanning." + bug: "319604673" metadata { purpose: PURPOSE_BUGFIX } } flag { - name: "enable_screen_off_scanning" + name: "enable_privileged_routing_for_media_routing_control" is_exported: true namespace: "media_solutions" - description: "Enable new MediaRouter2 API to enable watch companion apps to scan while the phone screen is off." - bug: "281072508" + description: "Allow access to privileged routing capabilities to MEDIA_ROUTING_CONTROL holders." + bug: "305919655" } flag { - name: "enable_null_session_in_media_browser_service" + name: "enable_rlp_callbacks_in_media_router2" + is_exported: true namespace: "media_solutions" - description: "Enables apps owning a MediaBrowserService to disconnect all connected browsers." - bug: "185136506" + description: "Make RouteListingPreference getter and callbacks public in MediaRouter2." + bug: "281067101" } flag { - name: "enable_prevention_of_manager_scans_when_no_apps_scan" + name: "enable_screen_off_scanning" + is_exported: true namespace: "media_solutions" - description: "Prevents waking up route providers when no apps are scanning, even if SysUI or Settings are scanning." - bug: "319604673" - metadata { - purpose: PURPOSE_BUGFIX - } + description: "Enable new MediaRouter2 API to enable watch companion apps to scan while the phone screen is off." + bug: "281072508" } flag { - name: "enable_full_scan_with_media_content_control" - namespace: "media_better_together" - description: "Allows holders of the MEDIA_CONTENT_CONTROL permission to scan for routes while not in the foreground." - bug: "352401364" - metadata { - purpose: PURPOSE_BUGFIX - } + name: "enable_use_of_bluetooth_device_get_alias_for_mr2info_get_name" + namespace: "media_solutions" + description: "Use BluetoothDevice.getAlias to populate the name of Bluetooth MediaRoute2Infos." + bug: "314324170" } flag { - name: "enable_audio_input_device_routing_and_volume_control" - namespace: "media_better_together" - description: "Allows audio input devices routing and volume control via system settings." - bug: "355684672" + name: "enable_waiting_state_for_system_session_creation_request" + namespace: "media_solutions" + description: "Introduces a waiting state for the session creation request and prevents it from early failing when the selectedRoute from the bluetooth stack doesn't match the pending request route id." + bug: "307723189" } flag { - name: "enable_mirroring_in_media_router_2" - namespace: "media_better_together" - description: "Enables support for mirroring routes in the MediaRouter2 framework, allowing Output Switcher to offer mirroring routes." - bug: "362507305" + name: "fallback_to_default_handling_when_media_session_has_fixed_volume_handling" + namespace: "media_solutions" + description: "Fallbacks to the default handling for volume adjustment when media session has fixed volume handling and its app is in the foreground and setting a media controller." + bug: "293743975" } diff --git a/media/java/android/media/flags/projection.aconfig b/media/java/android/media/flags/projection.aconfig index 17d1ff6a86a7..1bb9a8e1d6d3 100644 --- a/media/java/android/media/flags/projection.aconfig +++ b/media/java/android/media/flags/projection.aconfig @@ -18,3 +18,10 @@ flag { bug: "362720120" is_exported: true } + +flag { + namespace: "media_projection" + name: "stop_media_projection_on_call_end" + description: "Stops MediaProjection sessions when a call ends" + bug: "368336349" +}
\ No newline at end of file diff --git a/media/java/android/media/quality/AmbientBacklightEvent.java b/media/java/android/media/quality/AmbientBacklightEvent.java index 5c11def43209..273f21e01f86 100644 --- a/media/java/android/media/quality/AmbientBacklightEvent.java +++ b/media/java/android/media/quality/AmbientBacklightEvent.java @@ -40,7 +40,7 @@ public final class AmbientBacklightEvent implements Parcelable { @IntDef({AMBIENT_BACKLIGHT_EVENT_ENABLED, AMBIENT_BACKLIGHT_EVENT_DISABLED, AMBIENT_BACKLIGHT_EVENT_METADATA, AMBIENT_BACKLIGHT_EVENT_INTERRUPTED}) - public @interface AmbientBacklightEventTypes {} + public @interface Type {} /** * Event type for ambient backlight events. The ambient backlight is enabled. @@ -69,9 +69,9 @@ public final class AmbientBacklightEvent implements Parcelable { private final AmbientBacklightMetadata mMetadata; /** - * Constructor of AmbientBacklightEvent. + * Constructs AmbientBacklightEvent. */ - public AmbientBacklightEvent(int eventType, + public AmbientBacklightEvent(@Type int eventType, @Nullable AmbientBacklightMetadata metadata) { mEventType = eventType; mMetadata = metadata; @@ -85,6 +85,7 @@ public final class AmbientBacklightEvent implements Parcelable { /** * Gets event type. */ + @Type public int getEventType() { return mEventType; } diff --git a/media/java/android/media/quality/AmbientBacklightMetadata.java b/media/java/android/media/quality/AmbientBacklightMetadata.java index 9c11f9a3e560..5cea10d2de43 100644 --- a/media/java/android/media/quality/AmbientBacklightMetadata.java +++ b/media/java/android/media/quality/AmbientBacklightMetadata.java @@ -29,6 +29,9 @@ import java.util.Arrays; /** * Metadata of ambient backlight. + * + * <p>A metadata instance is sent from ambient backlight hardware in a {@link AmbientBacklightEvent} + * with {@link AmbientBacklightEvent#AMBIENT_BACKLIGHT_EVENT_METADATA}. * @hide */ @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) @@ -44,10 +47,15 @@ public final class AmbientBacklightMetadata implements Parcelable { private final int[] mZonesColors; /** - * Constructor of AmbientBacklightMetadata. + * Constructs AmbientBacklightMetadata. */ - public AmbientBacklightMetadata(@NonNull String packageName, int compressAlgorithm, - int source, int colorFormat, int horizontalZonesNumber, int verticalZonesNumber, + public AmbientBacklightMetadata( + @NonNull String packageName, + @AmbientBacklightSettings.CompressAlgorithm int compressAlgorithm, + @AmbientBacklightSettings.Source int source, + @PixelFormat.Format int colorFormat, + int horizontalZonesNumber, + int verticalZonesNumber, @NonNull int[] zonesColors) { mPackageName = packageName; mCompressAlgorithm = compressAlgorithm; @@ -69,7 +77,7 @@ public final class AmbientBacklightMetadata implements Parcelable { } /** - * Gets package name. + * Gets package name of the metadata. * @hide */ @NonNull @@ -102,7 +110,9 @@ public final class AmbientBacklightMetadata implements Parcelable { } /** - * Gets the number of lights in each horizontal zone. + * Gets the number of horizontal color zones. + * + * <p>A color zone is a group of lights that always display the same color. */ @IntRange(from = 0) public int getHorizontalZonesNumber() { @@ -110,7 +120,9 @@ public final class AmbientBacklightMetadata implements Parcelable { } /** - * Gets the number of lights in each vertical zone. + * Gets the number of vertical color zones. + * + * <p>A color zone is a group of lights that always display the same color. */ @IntRange(from = 0) public int getVerticalZonesNumber() { @@ -118,10 +130,11 @@ public final class AmbientBacklightMetadata implements Parcelable { } /** + * Gets color data of vertical color zones. * @hide */ @NonNull - public int[] getZonesColors() { + public int[] getVerticalZonesColors() { return mZonesColors; } diff --git a/media/java/android/media/quality/AmbientBacklightSettings.java b/media/java/android/media/quality/AmbientBacklightSettings.java index 4ed7bc79fdca..d904cf728da7 100644 --- a/media/java/android/media/quality/AmbientBacklightSettings.java +++ b/media/java/android/media/quality/AmbientBacklightSettings.java @@ -30,7 +30,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * Settings for ambient backlight. + * Settings to configure ambient backlight hardware. * @hide */ @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) @@ -124,8 +124,13 @@ public final class AmbientBacklightSettings implements Parcelable { /** * Constructs AmbientBacklightSettings. */ - public AmbientBacklightSettings(int source, int maxFps, int colorFormat, - int horizontalZonesNumber, int verticalZonesNumber, boolean isLetterboxOmitted, + public AmbientBacklightSettings( + @Source int source, + int maxFps, + @PixelFormat.Format int colorFormat, + int horizontalZonesNumber, + int verticalZonesNumber, + boolean isLetterboxOmitted, int threshold) { mSource = source; mMaxFps = maxFps; @@ -171,7 +176,9 @@ public final class AmbientBacklightSettings implements Parcelable { } /** - * Gets the number of lights in each horizontal zone. + * Gets the number of horizontal color zones. + * + * <p>A color zone is a group of lights that always display the same color. */ @IntRange(from = 0) public int getHorizontalZonesNumber() { @@ -179,7 +186,9 @@ public final class AmbientBacklightSettings implements Parcelable { } /** - * Gets the number of lights in each vertical zone. + * Gets the number of vertical color zones. + * + * <p>A color zone is a group of lights that always display the same color. */ @IntRange(from = 0) public int getVerticalZonesNumber() { @@ -187,7 +196,11 @@ public final class AmbientBacklightSettings implements Parcelable { } /** - * Returns {@code true} if letter box is omitted; {@code false} otherwise. + * Returns {@code true} if the black portion of the screen in letter box mode is omitted; + * {@code false} otherwise. + * + * <p>Letter-box is a technique to keep the original aspect ratio when displayed on a screen + * with different aspect ratio. Black bars are added to the top and bottom. * @hide */ public boolean isLetterboxOmitted() { @@ -195,6 +208,10 @@ public final class AmbientBacklightSettings implements Parcelable { } /** + * Gets the detection threshold of the ambient light. + * + * <p>If the color of a color zone is changed by the difference is smaller than the threshold, + * the change is ignored. * @hide */ public int getThreshold() { diff --git a/media/java/android/media/quality/IMediaQualityManager.aidl b/media/java/android/media/quality/IMediaQualityManager.aidl index 250d59b7c2d7..aaedf21999f7 100644 --- a/media/java/android/media/quality/IMediaQualityManager.aidl +++ b/media/java/android/media/quality/IMediaQualityManager.aidl @@ -42,10 +42,12 @@ interface IMediaQualityManager { SoundProfile createSoundProfile(in SoundProfile pp); void updateSoundProfile(in String id, in SoundProfile pp); void removeSoundProfile(in String id); - SoundProfile getSoundProfileById(in String id); + SoundProfile getSoundProfile(in int type, in String name); List<SoundProfile> getSoundProfilesByPackage(in String packageName); List<SoundProfile> getAvailableSoundProfiles(); List<String> getSoundProfilePackageNames(); + List<String> getSoundProfileAllowList(); + void setSoundProfileAllowList(in List<String> packages); void registerPictureProfileCallback(in IPictureProfileCallback cb); void registerSoundProfileCallback(in ISoundProfileCallback cb); diff --git a/media/java/android/media/quality/ISoundProfileCallback.aidl b/media/java/android/media/quality/ISoundProfileCallback.aidl index 72d1524198fd..9043757316bc 100644 --- a/media/java/android/media/quality/ISoundProfileCallback.aidl +++ b/media/java/android/media/quality/ISoundProfileCallback.aidl @@ -17,6 +17,7 @@ package android.media.quality; +import android.media.quality.ParamCapability; import android.media.quality.SoundProfile; /** @@ -24,7 +25,9 @@ import android.media.quality.SoundProfile; * @hide */ oneway interface ISoundProfileCallback { - void onSoundProfileAdded(in long id, in SoundProfile p); - void onSoundProfileUpdated(in long id, in SoundProfile p); - void onSoundProfileRemoved(in long id, in SoundProfile p); + void onSoundProfileAdded(in String id, in SoundProfile p); + void onSoundProfileUpdated(in String id, in SoundProfile p); + void onSoundProfileRemoved(in String id, in SoundProfile p); + void onParamCapabilitiesChanged(in String id, in List<ParamCapability> caps); + void onError(in int err); } diff --git a/media/java/android/media/quality/MediaQualityContract.java b/media/java/android/media/quality/MediaQualityContract.java index f07ef873a0af..5fec86a81a53 100644 --- a/media/java/android/media/quality/MediaQualityContract.java +++ b/media/java/android/media/quality/MediaQualityContract.java @@ -23,7 +23,6 @@ import android.media.tv.flags.Flags; /** * The contract between the media quality service and applications. Contains definitions for the * commonly used parameter names. - * @hide */ @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) public class MediaQualityContract { @@ -42,9 +41,8 @@ public class MediaQualityContract { /** * Parameters picture quality. - * @hide */ - public static final class PictureQuality implements BaseParameters { + public static final class PictureQuality { /** * The brightness. * diff --git a/media/java/android/media/quality/MediaQualityManager.java b/media/java/android/media/quality/MediaQualityManager.java index 4d4526cf9925..41932ce02d4c 100644 --- a/media/java/android/media/quality/MediaQualityManager.java +++ b/media/java/android/media/quality/MediaQualityManager.java @@ -20,6 +20,7 @@ import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.media.tv.flags.Flags; @@ -37,7 +38,6 @@ import java.util.concurrent.Executor; /** * Central system API to the overall media quality, which arbitrates interaction between * applications and media quality service. - * @hide */ @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) @SystemService(Context.MEDIA_QUALITY_SERVICE) @@ -111,7 +111,7 @@ public final class MediaQualityManager { }; ISoundProfileCallback spCallback = new ISoundProfileCallback.Stub() { @Override - public void onSoundProfileAdded(long profileId, SoundProfile profile) { + public void onSoundProfileAdded(String profileId, SoundProfile profile) { synchronized (mLock) { for (SoundProfileCallbackRecord record : mSpCallbackRecords) { // TODO: filter callback record @@ -120,7 +120,7 @@ public final class MediaQualityManager { } } @Override - public void onSoundProfileUpdated(long profileId, SoundProfile profile) { + public void onSoundProfileUpdated(String profileId, SoundProfile profile) { synchronized (mLock) { for (SoundProfileCallbackRecord record : mSpCallbackRecords) { // TODO: filter callback record @@ -129,7 +129,7 @@ public final class MediaQualityManager { } } @Override - public void onSoundProfileRemoved(long profileId, SoundProfile profile) { + public void onSoundProfileRemoved(String profileId, SoundProfile profile) { synchronized (mLock) { for (SoundProfileCallbackRecord record : mSpCallbackRecords) { // TODO: filter callback record @@ -137,6 +137,24 @@ public final class MediaQualityManager { } } } + @Override + public void onParamCapabilitiesChanged(String profileId, List<ParamCapability> caps) { + synchronized (mLock) { + for (SoundProfileCallbackRecord record : mSpCallbackRecords) { + // TODO: filter callback record + record.postParamCapabilitiesChanged(profileId, caps); + } + } + } + @Override + public void onError(int err) { + synchronized (mLock) { + for (SoundProfileCallbackRecord record : mSpCallbackRecords) { + // TODO: filter callback record + record.postError(err); + } + } + } }; IAmbientBacklightCallback abCallback = new IAmbientBacklightCallback.Stub() { @Override @@ -162,7 +180,6 @@ public final class MediaQualityManager { /** * Registers a {@link PictureProfileCallback}. - * @hide */ public void registerPictureProfileCallback( @NonNull @CallbackExecutor Executor executor, @@ -176,7 +193,6 @@ public final class MediaQualityManager { /** * Unregisters the existing {@link PictureProfileCallback}. - * @hide */ public void unregisterPictureProfileCallback(@NonNull final PictureProfileCallback callback) { Preconditions.checkNotNull(callback); @@ -198,7 +214,6 @@ public final class MediaQualityManager { * * @return the corresponding picture profile if available; {@code null} if the name doesn't * exist. - * @hide */ @Nullable public PictureProfile getPictureProfile( @@ -214,8 +229,9 @@ public final class MediaQualityManager { /** * Gets profiles that available to the given package. * - * @hide @SystemApi + * @hide */ + @SystemApi @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) public List<PictureProfile> getPictureProfilesByPackage(@NonNull String packageName) { @@ -242,8 +258,9 @@ public final class MediaQualityManager { * Gets all package names whose picture profiles are available. * * @see #getPictureProfilesByPackage(String) - * @hide @SystemApi + * @hide */ + @SystemApi @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) public List<String> getPictureProfilePackageNames() { @@ -274,7 +291,6 @@ public final class MediaQualityManager { /** * Updates an existing picture profile and store it in the system. - * @hide */ public void updatePictureProfile(@NonNull String profileId, @NonNull PictureProfile pp) { try { @@ -287,7 +303,6 @@ public final class MediaQualityManager { /** * Removes a picture profile from the system. - * @hide */ public void removePictureProfile(@NonNull String profileId) { try { @@ -331,14 +346,17 @@ public final class MediaQualityManager { /** - * Gets sound profile by given profile ID. - * @return the corresponding sound profile if available; {@code null} if the ID doesn't - * exist or the profile is not accessible to the caller. + * Gets sound profile by given profile type and name. + * + * @return the corresponding sound profile if available; {@code null} if the name doesn't + * exist. * @hide */ - public SoundProfile getSoundProfileById(String profileId) { + @Nullable + public SoundProfile getSoundProfile( + @SoundProfile.ProfileType int type, @NonNull String name) { try { - return mService.getSoundProfileById(profileId); + return mService.getSoundProfile(type, name); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -349,8 +367,9 @@ public final class MediaQualityManager { * @SystemApi gets profiles that available to the given package * @hide */ + @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) - public List<SoundProfile> getSoundProfilesByPackage(String packageName) { + public List<SoundProfile> getSoundProfilesByPackage(@NonNull String packageName) { try { return mService.getSoundProfilesByPackage(packageName); } catch (RemoteException e) { @@ -362,6 +381,7 @@ public final class MediaQualityManager { * Gets profiles that available to the caller package * @hide */ + @NonNull public List<SoundProfile> getAvailableSoundProfiles() { try { return mService.getAvailableSoundProfiles(); @@ -371,9 +391,12 @@ public final class MediaQualityManager { } /** - * @SystemApi all stored sound profiles of all packages + * @SystemApi Gets all package names whose sound profiles are available. + * + * @see #getSoundProfilesByPackage(String) * @hide */ + @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) public List<String> getSoundProfilePackageNames() { try { @@ -387,12 +410,13 @@ public final class MediaQualityManager { /** * Creates a sound profile and store it in the system. * - * @return the stored profile with an assigned profile ID. + * <p>If the profile is created successfully, + * {@link SoundProfileCallback#onSoundProfileAdded(long, SoundProfile)} is invoked. * @hide */ - public SoundProfile createSoundProfile(SoundProfile sp) { + public void createSoundProfile(@NonNull SoundProfile sp) { try { - return mService.createSoundProfile(sp); + mService.createSoundProfile(sp); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -403,7 +427,7 @@ public final class MediaQualityManager { * Updates an existing sound profile and store it in the system. * @hide */ - public void updateSoundProfile(String profileId, SoundProfile sp) { + public void updateSoundProfile(@NonNull String profileId, @NonNull SoundProfile sp) { try { mService.updateSoundProfile(profileId, sp); } catch (RemoteException e) { @@ -416,7 +440,7 @@ public final class MediaQualityManager { * Removes a sound profile from the system. * @hide */ - public void removeSoundProfile(String profileId) { + public void removeSoundProfile(@NonNull String profileId) { try { mService.removeSoundProfile(profileId); } catch (RemoteException e) { @@ -426,7 +450,6 @@ public final class MediaQualityManager { /** * Gets capability information of the given parameters. - * @hide */ @NonNull public List<ParamCapability> getParamCapabilities(@NonNull List<String> names) { @@ -444,6 +467,7 @@ public final class MediaQualityManager { * @see #removePictureProfile(String) * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) @NonNull public List<String> getPictureProfileAllowList() { @@ -458,6 +482,7 @@ public final class MediaQualityManager { * Sets the allowlist of packages that can create and removed picture profiles * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) public void setPictureProfileAllowList(@NonNull List<String> packageNames) { try { @@ -468,6 +493,36 @@ public final class MediaQualityManager { } /** + * Gets the allowlist of packages that can create and removed sound profiles + * + * @see #createSoundProfile(SoundProfile) + * @see #removeSoundProfile(String) + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) + @NonNull + public List<String> getSoundProfileAllowList() { + try { + return mService.getSoundProfileAllowList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Sets the allowlist of packages that can create and removed sound profiles + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) + public void setSoundProfileAllowList(@NonNull List<String> packageNames) { + try { + mService.setSoundProfileAllowList(packageNames); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Returns {@code true} if media quality HAL is implemented; {@code false} otherwise. * @hide */ @@ -567,6 +622,7 @@ public final class MediaQualityManager { /** * Registers a {@link AmbientBacklightCallback}. + * @hide */ public void registerAmbientBacklightCallback( @NonNull @CallbackExecutor Executor executor, @@ -580,6 +636,7 @@ public final class MediaQualityManager { /** * Unregisters the existing {@link AmbientBacklightCallback}. + * @hide */ public void unregisterAmbientBacklightCallback( @NonNull final AmbientBacklightCallback callback) { @@ -600,6 +657,7 @@ public final class MediaQualityManager { * Set the ambient backlight settings. * * @param settings The settings to use for the backlight detector. + * @hide */ public void setAmbientBacklightSettings( @NonNull AmbientBacklightSettings settings) { @@ -615,6 +673,7 @@ public final class MediaQualityManager { * Enables or disables the ambient backlight detection. * * @param enabled {@code true} to enable, {@code false} to disable. + * @hide */ public void setAmbientBacklightEnabled(boolean enabled) { try { @@ -698,7 +757,7 @@ public final class MediaQualityManager { return mCallback; } - public void postSoundProfileAdded(final long id, SoundProfile profile) { + public void postSoundProfileAdded(final String id, SoundProfile profile) { mExecutor.execute(new Runnable() { @Override @@ -708,7 +767,7 @@ public final class MediaQualityManager { }); } - public void postSoundProfileUpdated(final long id, SoundProfile profile) { + public void postSoundProfileUpdated(final String id, SoundProfile profile) { mExecutor.execute(new Runnable() { @Override public void run() { @@ -717,7 +776,7 @@ public final class MediaQualityManager { }); } - public void postSoundProfileRemoved(final long id, SoundProfile profile) { + public void postSoundProfileRemoved(final String id, SoundProfile profile) { mExecutor.execute(new Runnable() { @Override public void run() { @@ -725,6 +784,24 @@ public final class MediaQualityManager { } }); } + + public void postParamCapabilitiesChanged(final String id, List<ParamCapability> caps) { + mExecutor.execute(new Runnable() { + @Override + public void run() { + mCallback.onParamCapabilitiesChanged(id, caps); + } + }); + } + + public void postError(int error) { + mExecutor.execute(new Runnable() { + @Override + public void run() { + mCallback.onError(error); + } + }); + } } private static final class AmbientBacklightCallbackRecord { @@ -751,8 +828,7 @@ public final class MediaQualityManager { } /** - * Callback used to monitor status of picture profiles. - * @hide + * Callback used to monitor status of picture profiles */ public abstract static class PictureProfileCallback { /** @@ -760,7 +836,6 @@ public final class MediaQualityManager { * * @param profileId the ID of the profile. * @param profile the newly added profile. - * @hide */ public void onPictureProfileAdded( @NonNull String profileId, @NonNull PictureProfile profile) { @@ -771,7 +846,6 @@ public final class MediaQualityManager { * * @param profileId the ID of the profile. * @param profile the profile with updated info. - * @hide */ public void onPictureProfileUpdated( @NonNull String profileId, @NonNull PictureProfile profile) { @@ -782,7 +856,6 @@ public final class MediaQualityManager { * * @param profileId the ID of the profile. * @param profile the removed profile. - * @hide */ public void onPictureProfileRemoved( @NonNull String profileId, @NonNull PictureProfile profile) { @@ -792,7 +865,6 @@ public final class MediaQualityManager { * This is invoked when an issue has occurred. * * @param errorCode the error code - * @hide */ public void onError(@PictureProfile.ErrorCode int errorCode) { } @@ -801,12 +873,12 @@ public final class MediaQualityManager { * This is invoked when parameter capabilities has been changed due to status changes of the * content. * - * @param profileId the ID of the profile used by the media content. + * @param profileId the ID of the profile used by the media content. {@code null} if there + * is no associated profile * @param updatedCaps the updated capabilities. - * @hide */ public void onParamCapabilitiesChanged( - @NonNull String profileId, @NonNull List<ParamCapability> updatedCaps) { + @Nullable String profileId, @NonNull List<ParamCapability> updatedCaps) { } } @@ -816,29 +888,64 @@ public final class MediaQualityManager { */ public abstract static class SoundProfileCallback { /** + * This is invoked when a sound profile has been added. + * + * @param profileId the ID of the profile. + * @param profile the newly added profile. * @hide */ - public void onSoundProfileAdded(long id, SoundProfile profile) { + public void onSoundProfileAdded( + @NonNull String profileId, @NonNull SoundProfile profile) { } + /** + * This is invoked when a sound profile has been updated. + * + * @param profileId the ID of the profile. + * @param profile the profile with updated info. * @hide */ - public void onSoundProfileUpdated(long id, SoundProfile profile) { + public void onSoundProfileUpdated( + @NonNull String profileId, @NonNull SoundProfile profile) { } + /** + * This is invoked when a sound profile has been removed. + * + * @param profileId the ID of the profile. + * @param profile the removed profile. * @hide */ - public void onSoundProfileRemoved(long id, SoundProfile profile) { + public void onSoundProfileRemoved( + @NonNull String profileId, @NonNull SoundProfile profile) { } + /** + * This is invoked when an issue has occurred. + * + * @param errorCode the error code * @hide */ - public void onError(int errorCode) { + public void onError(@SoundProfile.ErrorCode int errorCode) { + } + + /** + * This is invoked when parameter capabilities has been changed due to status changes of the + * content. + * + * @param profileId the ID of the profile used by the media content. {@code null} if there + * is no associated profile + * @param updatedCaps the updated capabilities. + * @hide + */ + public void onParamCapabilitiesChanged( + @Nullable String profileId, @NonNull List<ParamCapability> updatedCaps) { } } /** * Callback used to monitor status of ambient backlight. + * @hide */ public abstract static class AmbientBacklightCallback { /** diff --git a/media/java/android/media/quality/ParamCapability.java b/media/java/android/media/quality/ParamCapability.java index 0b698a9c1ad2..ed11abd28379 100644 --- a/media/java/android/media/quality/ParamCapability.java +++ b/media/java/android/media/quality/ParamCapability.java @@ -31,7 +31,6 @@ import java.lang.annotation.RetentionPolicy; /** * Capability info of media quality parameters - * @hide */ @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) public final class ParamCapability implements Parcelable { diff --git a/media/java/android/media/quality/PictureProfile.java b/media/java/android/media/quality/PictureProfile.java index 2be47dd87ef2..dcb4222c3eaf 100644 --- a/media/java/android/media/quality/PictureProfile.java +++ b/media/java/android/media/quality/PictureProfile.java @@ -18,11 +18,12 @@ package android.media.quality; import android.annotation.FlaggedApi; import android.annotation.IntDef; +import android.annotation.SystemApi; import android.media.tv.TvInputInfo; import android.media.tv.flags.Flags; -import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.os.PersistableBundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -33,7 +34,6 @@ import java.lang.annotation.RetentionPolicy; /** * Profile for picture quality. - * @hide */ @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) public final class PictureProfile implements Parcelable { @@ -47,7 +47,7 @@ public final class PictureProfile implements Parcelable { @NonNull private final String mPackageName; @NonNull - private final Bundle mParams; + private final PersistableBundle mParams; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -59,14 +59,14 @@ public final class PictureProfile implements Parcelable { /** * System profile type. * - * <p>A profile of system type is managed by the system, and readable to the package define in + * <p>A profile of system type is managed by the system, and readable to the package returned by * {@link #getPackageName()}. */ public static final int TYPE_SYSTEM = 1; /** * Application profile type. * - * <p>A profile of application type is managed by the package define in + * <p>A profile of application type is managed by the package returned by * {@link #getPackageName()}. */ public static final int TYPE_APPLICATION = 2; @@ -84,13 +84,11 @@ public final class PictureProfile implements Parcelable { /** * Error code for unknown errors. - * @hide */ public static final int ERROR_UNKNOWN = 0; /** * Error code for missing necessary permission to handle the profiles. - * @hide */ public static final int ERROR_NO_PERMISSION = 1; @@ -99,13 +97,11 @@ public final class PictureProfile implements Parcelable { * * @see #getProfileType() * @see #getName() - * @hide */ public static final int ERROR_DUPLICATE = 2; /** * Error code for invalid argument. - * @hide */ public static final int ERROR_INVALID_ARGUMENT = 3; @@ -114,7 +110,6 @@ public final class PictureProfile implements Parcelable { * list. * * @see MediaQualityManager#getPictureProfileAllowList() - * @hide */ public static final int ERROR_NOT_ALLOWLISTED = 4; @@ -125,7 +120,7 @@ public final class PictureProfile implements Parcelable { mName = in.readString(); mInputId = in.readString(); mPackageName = in.readString(); - mParams = in.readBundle(); + mParams = in.readPersistableBundle(); } @Override @@ -135,7 +130,7 @@ public final class PictureProfile implements Parcelable { dest.writeString(mName); dest.writeString(mInputId); dest.writeString(mPackageName); - dest.writeBundle(mParams); + dest.writePersistableBundle(mParams); } @Override @@ -168,7 +163,7 @@ public final class PictureProfile implements Parcelable { @NonNull String name, @Nullable String inputId, @NonNull String packageName, - @NonNull Bundle params) { + @NonNull PersistableBundle params) { this.mId = id; this.mType = type; this.mName = name; @@ -251,13 +246,12 @@ public final class PictureProfile implements Parcelable { * {@link MediaQualityContract.PictureQuality}. */ @NonNull - public Bundle getParameters() { - return new Bundle(mParams); + public PersistableBundle getParameters() { + return new PersistableBundle(mParams); } /** * A builder for {@link PictureProfile}. - * @hide */ public static final class Builder { @Nullable @@ -270,7 +264,7 @@ public final class PictureProfile implements Parcelable { @NonNull private String mPackageName; @NonNull - private Bundle mParams; + private PersistableBundle mParams; /** * Creates a new Builder. @@ -291,8 +285,6 @@ public final class PictureProfile implements Parcelable { mParams = p.getParameters(); } - /* @hide using by MediaQualityService */ - /** * Only used by system to assign the ID. * @hide @@ -306,8 +298,9 @@ public final class PictureProfile implements Parcelable { /** * Sets profile type. * - * @hide @SystemApi + * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) @NonNull public Builder setProfileType(@ProfileType int value) { @@ -320,8 +313,9 @@ public final class PictureProfile implements Parcelable { * * @see PictureProfile#getInputId() * - * @hide @SystemApi + * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) @NonNull public Builder setInputId(@NonNull String value) { @@ -334,8 +328,9 @@ public final class PictureProfile implements Parcelable { * * @see PictureProfile#getPackageName() * - * @hide @SystemApi + * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE) @NonNull public Builder setPackageName(@NonNull String value) { @@ -349,8 +344,8 @@ public final class PictureProfile implements Parcelable { * @see PictureProfile#getParameters() */ @NonNull - public Builder setParameters(@NonNull Bundle params) { - mParams = new Bundle(params); + public Builder setParameters(@NonNull PersistableBundle params) { + mParams = new PersistableBundle(params); return this; } diff --git a/media/java/android/media/quality/SoundProfile.java b/media/java/android/media/quality/SoundProfile.java index 20d117bf15cf..de93afe4316f 100644 --- a/media/java/android/media/quality/SoundProfile.java +++ b/media/java/android/media/quality/SoundProfile.java @@ -17,54 +17,119 @@ package android.media.quality; import android.annotation.FlaggedApi; +import android.annotation.IntDef; +import android.media.tv.TvInputInfo; import android.media.tv.flags.Flags; -import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; +import android.os.PersistableBundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresPermission; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** + * Profile for sound quality. * @hide */ @FlaggedApi(Flags.FLAG_MEDIA_QUALITY_FW) public class SoundProfile implements Parcelable { @Nullable - private Long mId; + private String mId; + private final int mType; @NonNull private final String mName; @Nullable private final String mInputId; - @Nullable + @NonNull private final String mPackageName; @NonNull - private final Bundle mParams; + private final PersistableBundle mParams; - protected SoundProfile(Parcel in) { - if (in.readByte() == 0) { - mId = null; - } else { - mId = in.readLong(); - } + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = false, prefix = "TYPE_", value = { + TYPE_SYSTEM, + TYPE_APPLICATION}) + public @interface ProfileType {} + + /** + * System profile type. + * + * <p>A profile of system type is managed by the system, and readable to the package returned by + * {@link #getPackageName()}. + */ + public static final int TYPE_SYSTEM = 1; + /** + * Application profile type. + * + * <p>A profile of application type is managed by the package returned by + * {@link #getPackageName()}. + */ + public static final int TYPE_APPLICATION = 2; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(flag = false, prefix = "ERROR_", value = { + ERROR_UNKNOWN, + ERROR_NO_PERMISSION, + ERROR_DUPLICATE, + ERROR_INVALID_ARGUMENT, + ERROR_NOT_ALLOWLISTED + }) + public @interface ErrorCode {} + + /** + * Error code for unknown errors. + */ + public static final int ERROR_UNKNOWN = 0; + + /** + * Error code for missing necessary permission to handle the profiles. + */ + public static final int ERROR_NO_PERMISSION = 1; + + /** + * Error code for creating a profile with existing profile type and name. + * + * @see #getProfileType() + * @see #getName() + */ + public static final int ERROR_DUPLICATE = 2; + + /** + * Error code for invalid argument. + */ + public static final int ERROR_INVALID_ARGUMENT = 3; + + /** + * Error code for the case when an operation requires an allowlist but the caller is not in the + * list. + * + * @see MediaQualityManager#getSoundProfileAllowList() + */ + public static final int ERROR_NOT_ALLOWLISTED = 4; + + protected SoundProfile(@NonNull Parcel in) { + mId = in.readString(); + mType = in.readInt(); mName = in.readString(); mInputId = in.readString(); mPackageName = in.readString(); - mParams = in.readBundle(); + mParams = in.readPersistableBundle(); } @Override - public void writeToParcel(Parcel dest, int flags) { - if (mId == null) { - dest.writeByte((byte) 0); - } else { - dest.writeByte((byte) 1); - dest.writeLong(mId); - } + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mId); + dest.writeInt(mType); dest.writeString(mName); dest.writeString(mInputId); dest.writeString(mPackageName); - dest.writeBundle(mParams); + dest.writePersistableBundle(mParams); } @Override @@ -72,6 +137,7 @@ public class SoundProfile implements Parcelable { return 0; } + @NonNull public static final Creator<SoundProfile> CREATOR = new Creator<SoundProfile>() { @Override public SoundProfile createFromParcel(Parcel in) { @@ -91,93 +157,164 @@ public class SoundProfile implements Parcelable { * @hide */ public SoundProfile( - @Nullable Long id, + @Nullable String id, + int type, @NonNull String name, @Nullable String inputId, - @Nullable String packageName, - @NonNull Bundle params) { + @NonNull String packageName, + @NonNull PersistableBundle params) { this.mId = id; + this.mType = type; this.mName = name; - com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, name); this.mInputId = inputId; this.mPackageName = packageName; this.mParams = params; } + /** + * Gets profile ID. + * + * <p>A profile ID is a globally unique ID generated and assigned by the system. For profile + * objects retrieved from system (e.g {@link MediaQualityManager#getAvailableSoundProfiles()}) + * this profile ID is non-null; For profiles built locally with {@link Builder}, it's + * {@code null}. + * + * @return the unique profile ID; {@code null} if the profile is built locally with + * {@link Builder}. + */ @Nullable - public Long getProfileId() { + public String getProfileId() { return mId; } + /** + * Only used by system to assign the ID. + * @hide + */ + public void setProfileId(String id) { + mId = id; + } + + /** + * Gets profile type. + */ + @ProfileType + public int getProfileType() { + return mType; + } + + /** + * Gets the profile name. + */ @NonNull public String getName() { return mName; } + /** + * Gets the input ID if the profile is for a TV input. + * + * @return the corresponding TV input ID; {@code null} if the profile is not associated with a + * TV input. + * + * @see TvInputInfo#getId() + */ @Nullable public String getInputId() { return mInputId; } + /** + * Gets the package name of this profile. + * + * <p>The package name defines the user of a profile. Only this specific package and system app + * can access to this profile. + * + * @return the package name; {@code null} if the profile is built locally using + * {@link Builder} and the package is not set. + */ @Nullable public String getPackageName() { return mPackageName; } + + /** + * Gets the parameters of this profile. + * + * <p>The keys of commonly used parameters can be found in + * {@link MediaQualityContract.SoundQuality}. + */ @NonNull - public Bundle getParameters() { - return new Bundle(mParams); + public PersistableBundle getParameters() { + return new PersistableBundle(mParams); } /** * A builder for {@link SoundProfile} + * @hide */ public static class Builder { @Nullable - private Long mId; + private String mId; + private int mType = TYPE_APPLICATION; @NonNull private String mName; @Nullable private String mInputId; - @Nullable + @NonNull private String mPackageName; @NonNull - private Bundle mParams; + private PersistableBundle mParams; /** * Creates a new Builder. - * - * @hide */ public Builder(@NonNull String name) { mName = name; - com.android.internal.util.AnnotationValidations.validate(NonNull.class, null, name); } /** - * Copy constructor. - * - * @hide + * Copy constructor of builder. */ public Builder(@NonNull SoundProfile p) { mId = null; // ID needs to be reset + mType = p.getProfileType(); mName = p.getName(); mPackageName = p.getPackageName(); mInputId = p.getInputId(); + mParams = p.getParameters(); } /** - * Sets profile ID. - * @hide using by MediaQualityService + * Only used by system to assign the ID. + * @hide */ @NonNull - public Builder setProfileId(@Nullable Long id) { + public Builder setProfileId(@Nullable String id) { mId = id; return this; } /** + * Sets profile type. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) + @NonNull + public Builder setProfileType(@ProfileType int value) { + mType = value; + return this; + } + + /** * Sets input ID. + * + * @see SoundProfile#getInputId() + * + * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) @NonNull public Builder setInputId(@NonNull String value) { mInputId = value; @@ -186,7 +323,12 @@ public class SoundProfile implements Parcelable { /** * Sets package name of the profile. + * + * @see SoundProfile#getPackageName() + * + * @hide */ + @RequiresPermission(android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE) @NonNull public Builder setPackageName(@NonNull String value) { mPackageName = value; @@ -195,12 +337,15 @@ public class SoundProfile implements Parcelable { /** * Sets profile parameters. + * + * @see SoundProfile#getParameters() */ @NonNull - public Builder setParameters(@NonNull Bundle params) { - mParams = new Bundle(params); + public Builder setParameters(@NonNull PersistableBundle params) { + mParams = new PersistableBundle(params); return this; } + /** * Builds the instance. */ @@ -209,6 +354,7 @@ public class SoundProfile implements Parcelable { SoundProfile o = new SoundProfile( mId, + mType, mName, mInputId, mPackageName, diff --git a/media/java/android/media/tv/TvInputServiceExtensionManager.java b/media/java/android/media/tv/TvInputServiceExtensionManager.java index 9442726508c6..b876bcf8cd7e 100644 --- a/media/java/android/media/tv/TvInputServiceExtensionManager.java +++ b/media/java/android/media/tv/TvInputServiceExtensionManager.java @@ -194,96 +194,78 @@ public final class TvInputServiceExtensionManager { public static final String ISCAN_INTERFACE = SCAN_PACKAGE + "IScanInterface"; /** * Interface that handles scan session and get/store related information. - * @hide */ public static final String ISCAN_SESSION = SCAN_PACKAGE + "IScanSession"; /** - * Interface that notifies changes related to scan session. - * @hide + * Interface that notifies changes related to a scan session. */ public static final String ISCAN_LISTENER = SCAN_PACKAGE + "IScanListener"; /** * Interface for setting HDPlus information. - * @hide */ public static final String IHDPLUS_INFO = SCAN_PACKAGE + "IHDPlusInfo"; /** * Interface for handling operator detection for scanning. - * @hide */ public static final String IOPERATOR_DETECTION = SCAN_PACKAGE + "IOperatorDetection"; /** - * Interface for changes related to operator detection searches. - * @hide + * Interface for notifying changes related to operator detection searches. */ public static final String IOPERATOR_DETECTION_LISTENER = SCAN_PACKAGE + "IOperatorDetectionListener"; /** * Interface for handling region channel list for scanning. - * @hide */ public static final String IREGION_CHANNEL_LIST = SCAN_PACKAGE + "IRegionChannelList"; /** - * Interface for changes related to changes in region channel list search. - * @hide + * Interface for notifying changes related to changes in region channel list search. */ public static final String IREGION_CHANNEL_LIST_LISTENER = SCAN_PACKAGE + "IRegionChannelListListener"; /** * Interface for handling target region information. - * @hide */ public static final String ITARGET_REGION = SCAN_PACKAGE + "ITargetRegion"; /** - * Interface for changes related to target regions during scanning. - * @hide + * Interface for detecting changes related to target regions. */ public static final String ITARGET_REGION_LISTENER = SCAN_PACKAGE + "ITargetRegionListener"; /** - * Interface for handling LCN conflict groups. - * @hide + * Interface for handling logical channel number conflict groups. */ public static final String ILCN_CONFLICT = SCAN_PACKAGE + "ILcnConflict"; /** - * Interface for detecting LCN conflicts during scanning. - * @hide + * Interface for notifying changes in handling logical channel number conflicts. */ public static final String ILCN_CONFLICT_LISTENER = SCAN_PACKAGE + "ILcnConflictListener"; /** - * Interface for handling LCN V2 channel list information. - * @hide + * Interface for handling the updated standard for assigning logical channel numbers. */ public static final String ILCNV2_CHANNEL_LIST = SCAN_PACKAGE + "ILcnV2ChannelList"; /** - * Interface for detecting LCN V2 channel list during scanning. - * @hide + * Interface for notifying changes in assigning logical channel numbers with updated standard. */ public static final String ILCNV2_CHANNEL_LIST_LISTENER = SCAN_PACKAGE + "ILcnV2ChannelListListener"; /** * Interface for handling favorite network related information. - * @hide */ public static final String IFAVORITE_NETWORK = SCAN_PACKAGE + "IFavoriteNetwork"; /** - * Interface for detecting favorite network during scanning. - * @hide + * Interface for notifying changes favorite network during scanning. */ public static final String IFAVORITE_NETWORK_LISTENER = SCAN_PACKAGE + "IFavoriteNetworkListener"; /** - * Interface for handling Turksat channel update system service. - * @hide + * Interface for handling Turksat(TKGS) channel update system service. */ public static final String ITKGS_INFO = SCAN_PACKAGE + "ITkgsInfo"; /** - * Interface for changes related to TKGS information. - * @hide + * Interface for notifying changes related to Turksat(TKGS) information. */ public static final String ITKGS_INFO_LISTENER = SCAN_PACKAGE + "ITkgsInfoListener"; /** * Interface for satellite search related to low noise block downconverter. - * @hide */ public static final String ISCAN_SAT_SEARCH = SCAN_PACKAGE + "IScanSatSearch"; /** @@ -295,113 +277,94 @@ public final class TvInputServiceExtensionManager { */ public static final String ICAM_APP_INFO_SERVICE = CAM_PACKAGE + "ICamAppInfoService"; /** - * Interface for changes on conditional access module app related information. - * @hide + * Interface for notifying changes on conditional access module app related information. */ public static final String ICAM_APP_INFO_LISTENER = CAM_PACKAGE + "ICamAppInfoListener"; /** * Interface for handling conditional access module related information. - * @hide */ public static final String ICAM_MONITORING_SERVICE = CAM_PACKAGE + "ICamMonitoringService"; /** - * Interface for changes on conditional access module related information. - * @hide + * Interface for notifying changes on conditional access module related information. */ public static final String ICAM_INFO_LISTENER = CAM_PACKAGE + "ICamInfoListener"; /** - * Interface for handling control of CI+ operations. - * @hide + * Interface for handling control of common interface plus operations. */ public static final String ICI_OPERATOR_INTERFACE = CAM_PACKAGE + "ICiOperatorInterface"; /** - * Interfaces for changes on CI+ operations. - * @hide + * Interfaces for notifying changes on common interface plus operations. */ public static final String ICI_OPERATOR_LISTENER = CAM_PACKAGE + "ICiOperatorListener"; /** * Interface for handling conditional access module profile related information. - * @hide */ public static final String ICAM_PROFILE_INTERFACE = CAM_PACKAGE + "ICamProfileInterface"; /** - * Interface for handling conditional access module DRM related information. - * @hide + * Interface for handling conditional access module digital rights management (DRM) + * related information. */ public static final String ICONTENT_CONTROL_SERVICE = CAM_PACKAGE + "IContentControlService"; /** - * Interface for changes on DRM. - * @hide + * Interface for notifying changes on digital rights management (DRM). */ public static final String ICAM_DRM_INFO_LISTENER = CAM_PACKAGE + "ICamDrmInfoListener"; /** * Interface for handling conditional access module pin related information. - * @hide */ public static final String ICAM_PIN_SERVICE = CAM_PACKAGE + "ICamPinService"; /** - * Interface for changes on conditional access module pin capability. - * @hide + * Interface for notifying changes on conditional access module pin capability. */ public static final String ICAM_PIN_CAPABILITY_LISTENER = CAM_PACKAGE + "ICamPinCapabilityListener"; /** - * Interface for changes on conditional access module pin status. - * @hide + * Interface for notifying changes on conditional access module pin status. */ public static final String ICAM_PIN_STATUS_LISTENER = CAM_PACKAGE + "ICamPinStatusListener"; /** * Interface for handling conditional access module host control service. - * @hide */ public static final String ICAM_HOST_CONTROL_SERVICE = CAM_PACKAGE + "ICamHostControlService"; /** * Interface for handling conditional access module ask release reply. - * @hide */ public static final String ICAM_HOST_CONTROL_ASK_RELEASE_REPLY_CALLBACK = CAM_PACKAGE + "ICamHostControlAskReleaseReplyCallback"; /** - * Interface for changes on conditional access module host control service. - * @hide + * Interface for notifying changes on conditional access module host control service. */ public static final String ICAM_HOST_CONTROL_INFO_LISTENER = CAM_PACKAGE + "ICamHostControlInfoListener"; /** * Interface for handling conditional access module host control service tune_quietly_flag. - * @hide */ public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG = CAM_PACKAGE + "ICamHostControlTuneQuietlyFlag"; /** - * Interface for changes on conditional access module host control service tune_quietly_flag. - * @hide + * Interface for notifying changes on conditional access module host control service + * tune_quietly_flag. */ public static final String ICAM_HOST_CONTROL_TUNE_QUIETLY_FLAG_LISTENER = CAM_PACKAGE + "ICamHostControlTuneQuietlyFlagListener"; /** - * Interface for handling conditional access module multi media interface. - * @hide + * Interface for handling conditional access module multi-media interface. */ public static final String IMMI_INTERFACE = CAM_PACKAGE + "IMmiInterface"; /** - * Interface for controlling conditional access module multi media session. - * @hide + * Interface for controlling conditional access module multi-media session. */ public static final String IMMI_SESSION = CAM_PACKAGE + "IMmiSession"; /** - * Interface for changes on conditional access module multi media session status. - * @hide + * Interface for notifying changes on conditional access module multi-media session status. */ public static final String IMMI_STATUS_CALLBACK = CAM_PACKAGE + "IMmiStatusCallback"; /** - * Interface for changes on conditional access app info related to entering menu. - * @hide + * Interface for notifying changes on conditional access app info related to entering menu. */ public static final String IENTER_MENU_ERROR_CALLBACK = CAM_PACKAGE + "IEnterMenuErrorCallback"; /** - * Interface for handling RRT downloadable rating data. - * @hide + * Interface for handling Region Rating Table downloadable rating data. */ public static final String IDOWNLOADABLE_RATING_TABLE_MONITOR = RATING_PACKAGE + "IDownloadableRatingTableMonitor"; @@ -410,64 +373,54 @@ public final class TvInputServiceExtensionManager { */ public static final String IRATING_INTERFACE = RATING_PACKAGE + "IRatingInterface"; /** - * Interface for handling PMT rating related information. - * @hide + * Interface for handling Program Map Table rating related information. */ public static final String IPMT_RATING_INTERFACE = RATING_PACKAGE + "IPmtRatingInterface"; /** - * Interface for changes on PMT rating related information. - * @hide + * Interface for notifying changes on Program Map Table rating related information. */ public static final String IPMT_RATING_LISTENER = RATING_PACKAGE + "IPmtRatingListener"; /** - * Interface for handling IVBI rating related information. - * @hide + * Interface for handling Vertical Blanking Interval rating related information. */ public static final String IVBI_RATING_INTERFACE = RATING_PACKAGE + "IVbiRatingInterface"; /** - * Interface for changes on IVBI rating related information. - * @hide + * Interface for notifying changes on Vertical Blanking Interval rating related information. */ public static final String IVBI_RATING_LISTENER = RATING_PACKAGE + "IVbiRatingListener"; /** * Interface for handling program rating related information. - * @hide */ public static final String IPROGRAM_INFO = RATING_PACKAGE + "IProgramInfo"; /** - * Interface for changes on program rating related information. - * @hide + * Interface for notifying changes on program rating related information. */ public static final String IPROGRAM_INFO_LISTENER = RATING_PACKAGE + "IProgramInfoListener"; /** * Interface for getting broadcast time related information. */ - public static final String IBROADCAST_TIME = TIME_PACKAGE + "BroadcastTime"; + public static final String IBROADCAST_TIME = TIME_PACKAGE + "IBroadcastTime"; /** * Interface for handling data service signal information on teletext. */ public static final String IDATA_SERVICE_SIGNAL_INFO = TELETEXT_PACKAGE + "IDataServiceSignalInfo"; /** - * Interface for changes on data service signal information on teletext. - * @hide + * Interface for notifying changes on data service signal information on teletext. */ public static final String IDATA_SERVICE_SIGNAL_INFO_LISTENER = TELETEXT_PACKAGE + "IDataServiceSignalInfoListener"; /** * Interface for handling teletext page information. - * @hide */ public static final String ITELETEXT_PAGE_SUB_CODE = TELETEXT_PACKAGE + "ITeletextPageSubCode"; /** * Interface for handling scan background service update. - * @hide */ public static final String ISCAN_BACKGROUND_SERVICE_UPDATE = SCAN_BSU_PACKAGE + "IScanBackgroundServiceUpdate"; /** - * Interface for changes on background service update - * @hide + * Interface for notifying changes on background service update */ public static final String ISCAN_BACKGROUND_SERVICE_UPDATE_LISTENER = SCAN_BSU_PACKAGE + "IScanBackgroundServiceUpdateListener"; @@ -484,98 +437,82 @@ public final class TvInputServiceExtensionManager { */ public static final String IHDMI_SIGNAL_INTERFACE = SIGNAL_PACKAGE + "IHdmiSignalInterface"; /** - * Interfaces for changes on HDMI signal information update. - * @hide + * Interfaces for notifying changes on HDMI signal information update. */ public static final String IHDMI_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE + "IHdmiSignalInfoListener"; /** * Interfaces for handling audio signal information update. - * @hide */ public static final String IAUDIO_SIGNAL_INFO = SIGNAL_PACKAGE + "IAudioSignalInfo"; /** * Interfaces for handling analog audio signal information update. - * @hide */ public static final String IANALOG_AUDIO_INFO = SIGNAL_PACKAGE + "IAnalogAudioInfo"; /** - * Interfaces for change on audio signal information update. - * @hide + * Interfaces for notifying changes on audio signal information update. */ public static final String IAUDIO_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE + "IAudioSignalInfoListener"; /** * Interfaces for handling video signal information update. - * @hide */ public static final String IVIDEO_SIGNAL_INFO = SIGNAL_PACKAGE + "IVideoSignalInfo"; /** - * Interfaces for changes on video signal information update. - * @hide + * Interfaces for notifying changes on video signal information update. */ public static final String IVIDEO_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE + "IVideoSignalInfoListener"; /** * Interfaces for handling service database updates. - * @hide */ public static final String ISERVICE_LIST_EDIT = SERVICE_DATABASE_PACKAGE + "IServiceListEdit"; /** - * Interfaces for changes on service database updates. + * Interfaces for notifying changes on service database updates. */ public static final String ISERVICE_LIST_EDIT_LISTENER = SERVICE_DATABASE_PACKAGE + "IServiceListEditListener"; /** * Interfaces for getting service database related information. - * @hide */ public static final String ISERVICE_LIST = SERVICE_DATABASE_PACKAGE + "IServiceList"; /** * Interfaces for transferring service database related information. - * @hide */ public static final String ISERVICE_LIST_TRANSFER_INTERFACE = SERVICE_DATABASE_PACKAGE + "IServiceListTransferInterface"; /** * Interfaces for exporting service database session. - * @hide */ public static final String ISERVICE_LIST_EXPORT_SESSION = SERVICE_DATABASE_PACKAGE + "IServiceListExportSession"; /** - * Interfaces for changes on exporting service database session. - * @hide + * Interfaces for notifying changes on exporting service database session. */ public static final String ISERVICE_LIST_EXPORT_LISTENER = SERVICE_DATABASE_PACKAGE + "IServiceListExportListener"; /** * Interfaces for importing service database session. - * @hide */ public static final String ISERVICE_LIST_IMPORT_SESSION = SERVICE_DATABASE_PACKAGE + "IServiceListImportSession"; /** - * Interfaces for changes on importing service database session. - * @hide + * Interfaces for notifying changes on importing service database session. */ public static final String ISERVICE_LIST_IMPORT_LISTENER = SERVICE_DATABASE_PACKAGE + "IServiceListImportListener"; /** * Interfaces for setting channel list resources. - * @hide */ public static final String ISERVICE_LIST_SET_CHANNEL_LIST_SESSION = SERVICE_DATABASE_PACKAGE + "IServiceListSetChannelListSession"; /** - * Interfaces for changes on setting channel list resources. - * @hide + * Interfaces for notifying changes on setting channel list resources. */ public static final String ISERVICE_LIST_SET_CHANNEL_LIST_LISTENER = SERVICE_DATABASE_PACKAGE + "IServiceListSetChannelListListener"; /** * Interfaces for transferring channel list resources. - * @hide */ public static final String ICHANNEL_LIST_TRANSFER = SERVICE_DATABASE_PACKAGE + "IChannelListTransfer"; @@ -584,14 +521,12 @@ public final class TvInputServiceExtensionManager { */ public static final String IRECORDED_CONTENTS = PVR_PACKAGE + "IRecordedContents"; /** - * Interfaces for changes on deleting record contents. - * @hide + * Interfaces for notifying changes on deleting record contents. */ public static final String IDELETE_RECORDED_CONTENTS_CALLBACK = PVR_PACKAGE + "IDeleteRecordedContentsCallback"; /** - * Interfaces for changes on getting record contents. - * @hide + * Interfaces for notifying changes on getting record contents. */ public static final String IGET_INFO_RECORDED_CONTENTS_CALLBACK = PVR_PACKAGE + "IGetInfoRecordedContentsCallback"; @@ -600,61 +535,51 @@ public final class TvInputServiceExtensionManager { */ public static final String IEVENT_MONITOR = EVENT_PACKAGE + "IEventMonitor"; /** - * Interfaces for changes on present event information. - * @hide + * Interfaces for notifying changes on present event information. */ public static final String IEVENT_MONITOR_LISTENER = EVENT_PACKAGE + "IEventMonitorListener"; /** * Interfaces for handling download event information. - * @hide */ public static final String IEVENT_DOWNLOAD = EVENT_PACKAGE + "IEventDownload"; /** - * Interfaces for changes on downloading event information. - * @hide + * Interfaces for notifying changes on downloading event information. */ public static final String IEVENT_DOWNLOAD_LISTENER = EVENT_PACKAGE + "IEventDownloadListener"; /** - * Interfaces for handling download event information for DVB and DTMB. - * @hide + * Interfaces for handling download event information for Digital Video Broadcast + * and Digital Terrestrial Multimedia Broadcast. */ public static final String IEVENT_DOWNLOAD_SESSION = EVENT_PACKAGE + "IEventDownloadSession"; /** * Interfaces for handling analog color system. - * @hide */ public static final String IANALOG_ATTRIBUTE_INTERFACE = ANALOG_PACKAGE + "IAnalogAttributeInterface"; /** * Interfaces for monitoring channel tuned information. - * @hide */ public static final String ICHANNEL_TUNED_INTERFACE = TUNE_PACKAGE + "IChannelTunedInterface"; /** - * Interfaces for changes on channel tuned information. - * @hide + * Interfaces for notifying changes on channel tuned information. */ public static final String ICHANNEL_TUNED_LISTENER = TUNE_PACKAGE + "IChannelTunedListener"; /** * Interfaces for handling tuner frontend signal info. - * @hide */ public static final String ITUNER_FRONTEND_SIGNAL_INFO_INTERFACE = SIGNAL_PACKAGE + "ITunerFrontendSignalInfoInterface"; /** - * Interfaces for changes on tuner frontend signal info. - * @hide + * Interfaces for notifying changes on tuner frontend signal info. */ public static final String ITUNER_FRONTEND_SIGNAL_INFO_LISTENER = SIGNAL_PACKAGE + "ITunerFrontendSignalInfoListener"; /** * Interfaces for handling mux tune operations. - * @hide */ public static final String IMUX_TUNE_SESSION = TUNE_PACKAGE + "IMuxTuneSession"; /** * Interfaces for initing mux tune session. - * @hide */ public static final String IMUX_TUNE = TUNE_PACKAGE + "IMuxTune"; diff --git a/media/java/android/media/tv/ad/TvAdView.java b/media/java/android/media/tv/ad/TvAdView.java index dd2a534676d8..ff0279fef99e 100644 --- a/media/java/android/media/tv/ad/TvAdView.java +++ b/media/java/android/media/tv/ad/TvAdView.java @@ -240,6 +240,38 @@ public class TvAdView extends ViewGroup { } } + /** + * Controls whether the TvAdView's surface is placed on top of other regular surface views in + * the window (but still behind the window itself). + * + * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}. + * + * @param isMediaOverlay {@code true} to be on top of another regular surface, {@code false} + * otherwise. + */ + @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) + public void setZOrderMediaOverlay(boolean isMediaOverlay) { + if (mSurfaceView != null) { + mSurfaceView.setZOrderOnTop(false); + mSurfaceView.setZOrderMediaOverlay(isMediaOverlay); + } + } + + /** + * Controls whether the TvAdView's surface is placed on top of its window. + * + * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}. + * + * @param onTop {@code true} to be on top of its window, {@code false} otherwise. + */ + @FlaggedApi(Flags.FLAG_ENABLE_AD_SERVICE_FW) + public void setZOrderOnTop(boolean onTop) { + if (mSurfaceView != null) { + mSurfaceView.setZOrderMediaOverlay(false); + mSurfaceView.setZOrderOnTop(onTop); + } + } + private void resetSurfaceView() { if (mSurfaceView != null) { mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback); diff --git a/media/java/android/media/tv/extension/oad/IOadUpdateInterface.aidl b/media/java/android/media/tv/extension/oad/IOadUpdateInterface.aidl new file mode 100644 index 000000000000..2a2e71a53993 --- /dev/null +++ b/media/java/android/media/tv/extension/oad/IOadUpdateInterface.aidl @@ -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 android.media.tv.extension.oad; + +/** + * @hide + */ +interface IOadUpdateInterface { + // Enable or disable the OAD function. + void setOadStatus(boolean enable); + // Get status of OAD function. + boolean getOadStatus(); + // Start OAD scan of all frequency in the program list. + void startScan(); + // Stop OAD scan of all frequency in the program list. + void stopScan(); + // Start OAD detect for the current channel. + void startDetect(); + // Stop OAD detect for the current channel. + void stopDetect(); + // Start OAD download after it has been detected or scanned. + void startDownload(); + // Stop OAD download. + void stopDownload(); + // Retrieves current OAD software version. + int getSoftwareVersion(); +} diff --git a/media/java/android/media/tv/extension/pvr/IDeleteRecordedContentsCallback.aidl b/media/java/android/media/tv/extension/pvr/IDeleteRecordedContentsCallback.aidl new file mode 100644 index 000000000000..62f151145472 --- /dev/null +++ b/media/java/android/media/tv/extension/pvr/IDeleteRecordedContentsCallback.aidl @@ -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 android.media.tv.extension.pvr; + +/** + * @hide + */ +oneway interface IDeleteRecordedContentsCallback { + void onRecordedContentsDeleted(in String[] contentUri, in int[] result); +} diff --git a/media/java/android/media/tv/extension/pvr/IGetInfoRecordedContentsCallback.aidl b/media/java/android/media/tv/extension/pvr/IGetInfoRecordedContentsCallback.aidl new file mode 100644 index 000000000000..64f8fc2188b7 --- /dev/null +++ b/media/java/android/media/tv/extension/pvr/IGetInfoRecordedContentsCallback.aidl @@ -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 android.media.tv.extension.pvr; + +/** + * @hide + */ +interface IGetInfoRecordedContentsCallback { + void onRecordedContentsGetInfo(int result); +} diff --git a/media/java/android/media/tv/extension/pvr/IRecordedContents.aidl b/media/java/android/media/tv/extension/pvr/IRecordedContents.aidl new file mode 100644 index 000000000000..74a15b8e0b94 --- /dev/null +++ b/media/java/android/media/tv/extension/pvr/IRecordedContents.aidl @@ -0,0 +1,36 @@ +/* + * 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 android.media.tv.extension.pvr; + +import android.media.tv.extension.pvr.IDeleteRecordedContentsCallback; +import android.media.tv.extension.pvr.IGetInfoRecordedContentsCallback; + + +/** + * @hide + */ +interface IRecordedContents { + // Delete recorded contents by URIs + // using callback to notify the result or any errors during the deletion process. + void deleteRecordedContents(in String[] contentUri, + in IDeleteRecordedContentsCallback callback); + // Get the channel lock status for recorded content identified by the URI provided in sync way. + int getRecordedContentsLockInfoSync(String contentUri); + // Get the channel lock status for recorded content identified by the URI provided in async way. + void getRecordedContentsLockInfoAsync(String contentUri, + in IGetInfoRecordedContentsCallback callback); +} diff --git a/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl b/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl new file mode 100644 index 000000000000..bf1a385f05ae --- /dev/null +++ b/media/java/android/media/tv/extension/rating/IDownloadableRatingTableMonitor.aidl @@ -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 android.media.tv.extension.rating; + +import android.os.Bundle; + +/** + * @hide + */ +interface IDownloadableRatingTableMonitor { + // Get RRT rating info on downloadable rating data + Bundle[] getTable(); +} diff --git a/media/java/android/media/tv/extension/rating/IPmtRatingInterface.aidl b/media/java/android/media/tv/extension/rating/IPmtRatingInterface.aidl new file mode 100644 index 000000000000..06cac3d0d411 --- /dev/null +++ b/media/java/android/media/tv/extension/rating/IPmtRatingInterface.aidl @@ -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 android.media.tv.extension.rating; + +import android.media.tv.extension.rating.IPmtRatingListener; + +/** + * @hide + */ +interface IPmtRatingInterface { + // Get Pmt rating information. + String getPmtRating(String sessionToken); + // Register a listener for pmt rating updates. + void addPmtRatingListener(String clientToken, in IPmtRatingListener listener); + // Remove the previously added IPmtRatingListener. + void removePmtRatingListener(in IPmtRatingListener listener); +} diff --git a/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl b/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl new file mode 100644 index 000000000000..d88ae9425f8c --- /dev/null +++ b/media/java/android/media/tv/extension/rating/IPmtRatingListener.aidl @@ -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 android.media.tv.extension.rating; + +/** + * @hide + */ +oneway interface IPmtRatingListener { + void onPmtRatingChanged(String sessionToken, String newTvContentRating); +} diff --git a/media/java/android/media/tv/extension/rating/IProgramRatingInfo.aidl b/media/java/android/media/tv/extension/rating/IProgramRatingInfo.aidl new file mode 100644 index 000000000000..a490491d7acc --- /dev/null +++ b/media/java/android/media/tv/extension/rating/IProgramRatingInfo.aidl @@ -0,0 +1,32 @@ +/* + * 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 android.media.tv.extension.rating; + +import android.media.tv.extension.rating.IProgramRatingInfoListener; +import android.os.Bundle; + +/** + * @hide + */ +interface IProgramRatingInfo { + // Register a listener to receive notifications when ProgramRatingInfo is updated. + void addProgramRatingInfoListener(String clientToken, in IProgramRatingInfoListener listener); + // Remove a listener for ProgramRatingInfo update notifications. + void removeProgramRatingInfoListener(in IProgramRatingInfoListener listener); + // Get ProgramRatingInfo that may only be obtained when viewing. + Bundle getProgramRatingInfo(String sessionToken); +} diff --git a/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl b/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl new file mode 100644 index 000000000000..6777cd3035d8 --- /dev/null +++ b/media/java/android/media/tv/extension/rating/IProgramRatingInfoListener.aidl @@ -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 android.media.tv.extension.rating; + +import android.os.Bundle; + +/** + * @hide + */ +interface IProgramRatingInfoListener { + void onProgramInfoChanged(String sessionToken,in Bundle changedProgramInfo); +} diff --git a/media/java/android/media/tv/extension/rating/IRatingInterface.aidl b/media/java/android/media/tv/extension/rating/IRatingInterface.aidl new file mode 100644 index 000000000000..d68fe763ef28 --- /dev/null +++ b/media/java/android/media/tv/extension/rating/IRatingInterface.aidl @@ -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 android.media.tv.extension.rating; + +import android.os.Bundle; + +/** + * @hide + */ +interface IRatingInterface { + // Get RRT rating information + Bundle getRRTRatingInfo(); + // Set RRT rating information when user select + boolean setRRTRatingInfo(in Bundle param); + // Reset RRT5 to clear information + boolean setResetRrt5(); +} diff --git a/media/java/android/media/tv/extension/rating/IVbiRatingInterface.aidl b/media/java/android/media/tv/extension/rating/IVbiRatingInterface.aidl new file mode 100644 index 000000000000..bad40676e8aa --- /dev/null +++ b/media/java/android/media/tv/extension/rating/IVbiRatingInterface.aidl @@ -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 android.media.tv.extension.rating; + +import android.media.tv.extension.rating.IVbiRatingListener; + +/** + * @hide + */ +interface IVbiRatingInterface { + // Get Vbi rating. + String getVbiRating(String sessionToken); + // Register a listener for Vbi rating updates. + void addVbiRatingListener(String clientToken, in IVbiRatingListener listener); + // Remove the previously added VbiRatingListener. + void removeVbiRatingListener(in IVbiRatingListener listener); +} diff --git a/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl b/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl new file mode 100644 index 000000000000..36d523f97613 --- /dev/null +++ b/media/java/android/media/tv/extension/rating/IVbiRatingListener.aidl @@ -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 android.media.tv.extension.rating; + +/** + * @hide + */ +oneway interface IVbiRatingListener { + void onVbiRatingChanged(String sessionToken, String newTvContentRating); +} diff --git a/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl b/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl new file mode 100644 index 000000000000..ff78aa4be39c --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IFavoriteNetwork.aidl @@ -0,0 +1,36 @@ +/* + * 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 android.media.tv.extension.scan; + +import android.media.tv.extension.scan.IFavoriteNetworkListener; +import android.os.Bundle; + +/** + * Country: Norway + * Broadcast Type: BROADCAST_TYPE_DVB_T + * (Operator: RiksTV) + * + * @hide + */ +interface IFavoriteNetwork { + // Get the favorite network information,If there are no conflicts, the array of Bundle is empty. + Bundle[] getFavoriteNetworks(); + // Select and set one of two or more favorite networks detected by the service scan. + int setFavoriteNetwork(in Bundle favoriteNetworkSettings); + // Set the listener to be invoked when two or more favorite networks are detected. + int setListener(in IFavoriteNetworkListener listener); +} diff --git a/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl b/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl new file mode 100644 index 000000000000..699422493dd6 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IFavoriteNetworkListener.aidl @@ -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 android.media.tv.extension.scan; + +import android.os.Bundle; + +/** + * @hide + */ +oneway interface IFavoriteNetworkListener { + void onDetectFavoriteNetwork(in Bundle detectFavoriteNetworks); +} diff --git a/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl b/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl new file mode 100644 index 000000000000..cdf6e23f4b47 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IHDPlusInfo.aidl @@ -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 android.media.tv.extension.scan; + +/** + * @hide + */ +interface IHDPlusInfo { + // Specifying a HDPlusInfo and start a network scan. + int setHDPlusInfo(String isBlindScanContinue, String isHDMode); +} diff --git a/media/java/android/media/tv/extension/scan/ILcnConflict.aidl b/media/java/android/media/tv/extension/scan/ILcnConflict.aidl new file mode 100644 index 000000000000..5dff39eb5920 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/ILcnConflict.aidl @@ -0,0 +1,35 @@ +/* + * 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 android.media.tv.extension.scan; + +import android.media.tv.extension.scan.ILcnConflictListener; +import android.os.Bundle; + +/** + * Country: Italy, France + * Broadcast Type: BROADCAST_TYPE_DVB_T + * + * @hide + */ +interface ILcnConflict { + // Get the LCN conflict groups information, If there are no conflicts, the array of Bundle is empty. + Bundle[] getLcnConflictGroups(); + // Resolve LCN conflicts caused by service scans. + int resolveLcnConflict(in Bundle[] lcnConflictSettings); + // Set the listener to be invoked the LCN conflict event. + int setListener(in ILcnConflictListener listener); +} diff --git a/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl b/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl new file mode 100644 index 000000000000..6bbbeb8e1e06 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/ILcnConflictListener.aidl @@ -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 android.media.tv.extension.scan; + +import android.os.Bundle; + +/** + * @hide + */ +oneway interface ILcnConflictListener { + void onDetectLcnConflict(in Bundle detectLcnConflicts); +} diff --git a/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl b/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl new file mode 100644 index 000000000000..f9a9d345a575 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/ILcnV2ChannelList.aidl @@ -0,0 +1,35 @@ +/* + * 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 android.media.tv.extension.scan; + +import android.media.tv.extension.scan.ILcnV2ChannelListListener; +import android.os.Bundle; + +/** + * Country: (NorDig etc.) + * Broadcast Type: BROADCAST_TYPE_DVB_T, BROADCAST_TYPE_DVB_C + * + * @hide + */ +interface ILcnV2ChannelList { + // Get the LCN V2 channel list information. If there are no conflicts, the array of Bundle is empty. + Bundle[] getLcnV2ChannelLists(); + // Select and set one of two or more LCN V2 channel list detected by the service scan. + int setLcnV2ChannelList(in Bundle lcnV2ChannelListSettings); + // Set the listener to be invoked when two or more LCN V2 channel list are detected. + int setListener(in ILcnV2ChannelListListener listener); +} diff --git a/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl b/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl new file mode 100644 index 000000000000..cbdb83c656f4 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/ILcnV2ChannelListListener.aidl @@ -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 android.media.tv.extension.scan; + +import android.os.Bundle; + +/** + * @hide + */ +oneway interface ILcnV2ChannelListListener { + void onDetectLcnV2ChannelList(in Bundle detectLcnV2ChannelList); +} diff --git a/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl b/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl new file mode 100644 index 000000000000..770f8668983e --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IOperatorDetection.aidl @@ -0,0 +1,35 @@ +/* + * 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 android.media.tv.extension.scan; + +import android.media.tv.extension.scan.IOperatorDetectionListener; +import android.os.Bundle; + +/** + * Country: Any + * Broadcast Type: BROADCAST_TYPE_DVB_S + * (Operator: M7) + * + * @hide + */ +interface IOperatorDetection { + // Set the operator selected info for scanning. + int setOperatorDetection(in Bundle operatorSelected); + // Set the listener to be invoked when one or more operator detection has been detected by + // operator detection searches. + int setListener(in IOperatorDetectionListener listener); +} diff --git a/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl b/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl new file mode 100644 index 000000000000..7dcd46177c43 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IOperatorDetectionListener.aidl @@ -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 android.media.tv.extension.scan; + +import android.os.Bundle; + + +/** + * @hide + */ +oneway interface IOperatorDetectionListener { + void onDetectOperatorDetectionList(in Bundle[] detectOperatorDetectionList); +} diff --git a/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl b/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl new file mode 100644 index 000000000000..fe755f873110 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IRegionChannelList.aidl @@ -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 android.media.tv.extension.scan; + +import android.media.tv.extension.scan.IRegionChannelListListener; + +/** + * @hide + */ +interface IRegionChannelList { + // Set the region channel list for scanning. + int setRegionChannelList(String regionChannelList); + // Set the listener to be invoked when one or more region channel list has been detected by + // region channel list searches. + int setListener(in IRegionChannelListListener listener); +} diff --git a/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl b/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl new file mode 100644 index 000000000000..06b0eb5537a2 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IRegionChannelListListener.aidl @@ -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 android.media.tv.extension.scan; + +/** + * @hide + */ +oneway interface IRegionChannelListListener { + void onDetectRegionChannelList(in String[] detectRegionChannelList); +} diff --git a/media/java/android/media/tv/extension/scan/IScanInterface.aidl b/media/java/android/media/tv/extension/scan/IScanInterface.aidl new file mode 100644 index 000000000000..b44d1d243150 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IScanInterface.aidl @@ -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 android.media.tv.extension.scan; + +import android.media.tv.extension.scan.IScanListener; +import android.os.Bundle; + +/** + * @hide + */ +interface IScanInterface { + IBinder createSession(int broadcastType, String countryCode, String operator, + in IScanListener listener); + Bundle getParameters(int broadcastType, String countryCode, String operator, + in Bundle params); +} diff --git a/media/java/android/media/tv/extension/scan/IScanListener.aidl b/media/java/android/media/tv/extension/scan/IScanListener.aidl new file mode 100644 index 000000000000..2c4807f97c58 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IScanListener.aidl @@ -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 android.media.tv.extension.scan; + +import android.os.Bundle; + +/** + * @hide + */ +oneway interface IScanListener { + // notify events during scan. + void onEvent(in Bundle eventArgs); + // notify the scan progress. + void onScanProgress(String scanProgress, in Bundle scanProgressInfo); + // notify the scan completion. + void onScanCompleted(int scanResult); + // notify that the temporaily held channel list is stored. + void onStoreCompleted(int storeResult); +} diff --git a/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl b/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl new file mode 100644 index 000000000000..b8074fc4a9bd --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IScanSatSearch.aidl @@ -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 android.media.tv.extension.scan; + +/** + * For satellite search function. + * @hide + */ +interface IScanSatSearch { + // Set currecnt LNB as customized LNB, default LNB is universal LNB + int setCustomizedLnb(String customizedLnb); +} diff --git a/media/java/android/media/tv/extension/scan/IScanSession.aidl b/media/java/android/media/tv/extension/scan/IScanSession.aidl new file mode 100644 index 000000000000..d42eca1342b5 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/IScanSession.aidl @@ -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 android.media.tv.extension.scan; + +import android.os.Bundle; + +/** + * @hide + */ +interface IScanSession { + // Start a service scan. + int startScan(int broadcastType, String countryCode, String operator, in int[] frequency, + String scanType, String languageCode); + // Reset the scan information held in TIS. + int resetScan(); + // Cancel scan. + int cancelScan(); + + // Get available interface for created ScanExtension interface. + String[] getAvailableExtensionInterfaceNames(); + // Get extension interface for Scan. + IBinder getExtensionInterface(String name); + + // Clear the results of the service scan from the service database. + int clearServiceList(in Bundle optionalClearParams); + // Store the results of the service scan from the service database. + int storeServiceList(); + // Get a service information specified by the service information ID. + Bundle getServiceInfo(String serviceInfoId, in String[] keys); + // Get a service information ID list. + String[] getServiceInfoIdList(); + // Get a list of service info by the filter. + Bundle getServiceInfoList(in Bundle filterInfo, in String[] keys); + // Update the service information. + int updateServiceInfo(in Bundle serviceInfo); + // Updates the service information for the specified service information ID in array list. + int updateServiceInfoByList(in Bundle[] serviceInfo); + + /* DVBI specific functions */ + // Get all of the serviceLists, parsed from Local TV storage, Broadcast, USB file discovery. + Bundle getServiceLists(); + // Users choose one serviceList from the serviceLists, and install the services. + int setServiceList(int serviceListRecId); + // Get all of the packageData, parsed from the selected serviceList XML. + Bundle getPackageData(); + // Choose the package using package id and install the corresponding services. + int setPackage(String packageId); + // Get all of the countryRegionData, parsed from the selected serviceList XML. + Bundle getCountryRegionData(); + // Choose the countryRegion using countryRegion id, and install the corresponding services. + int setCountryRegion(String regionId); + // Get all of the regionData, parsed from the selected serviceList XML. + Bundle getRegionData(); + // Choose the region using the regionData id, and install the corresponding services. + int setRegion(String regionId); + + // Get unique session token for the scan. + String getSessionToken(); + // Release scan resource, the register listener will be released. + int release(); +} diff --git a/media/java/android/media/tv/extension/scan/ITargetRegion.aidl b/media/java/android/media/tv/extension/scan/ITargetRegion.aidl new file mode 100644 index 000000000000..417e12243b82 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/ITargetRegion.aidl @@ -0,0 +1,36 @@ +/* + * 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 android.media.tv.extension.scan; + +import android.media.tv.extension.scan.ITargetRegionListener; + +import android.os.Bundle; + +/** + * Country: U.K. + * Broadcast Type: BROADCAST_TYPE_DVB_T + * + * @hide + */ +interface ITargetRegion { + // Get the target regions information. If there are no conflicts, the array of Bundle is empty. + Bundle[] getTargetRegions(); + // Select and set one of two or more target region detected by the service scan. + int setTargetRegion(in Bundle targetRegionSettings); + // Set the listener to be invoked when two or more regions are detected. + int setListener(in ITargetRegionListener listener); +} diff --git a/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl b/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl new file mode 100644 index 000000000000..9d6aa8e8ea31 --- /dev/null +++ b/media/java/android/media/tv/extension/scan/ITargetRegionListener.aidl @@ -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 android.media.tv.extension.scan; + +import android.os.Bundle; + +/** + * @hide + */ +oneway interface ITargetRegionListener { + void onDetectTargetRegion(in Bundle detectTargetRegions); +} diff --git a/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl b/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl new file mode 100644 index 000000000000..f25952c1cbdc --- /dev/null +++ b/media/java/android/media/tv/extension/scan/ITkgsInfo.aidl @@ -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 android.media.tv.extension.scan; + +import android.media.tv.extension.scan.ITkgsInfoListener; +import android.os.Bundle; + +/** + * @hide + */ +interface ITkgsInfo { + int setPrefServiceList(String prefServiceList); + int setTkgsInfoListener(in ITkgsInfoListener listener); +} diff --git a/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl b/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl new file mode 100644 index 000000000000..e3dcf2d4c5ad --- /dev/null +++ b/media/java/android/media/tv/extension/scan/ITkgsInfoListener.aidl @@ -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 android.media.tv.extension.scan; + +/** + * @hide + */ +oneway interface ITkgsInfoListener { + void onServiceList(in String[] serviceList); + void onTableVersionUpdate(int tableVersion); + void onUserMessage(String strMessage); +} diff --git a/media/java/android/media/tv/extension/signal/IAnalogAudioInfo.aidl b/media/java/android/media/tv/extension/signal/IAnalogAudioInfo.aidl new file mode 100644 index 000000000000..742191ff3c05 --- /dev/null +++ b/media/java/android/media/tv/extension/signal/IAnalogAudioInfo.aidl @@ -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 android.media.tv.extension.signal; + +import android.os.Bundle; + +/** + * @hide + */ +interface IAnalogAudioInfo { + Bundle getAnalogAudioInfo(String sessionToken); +} diff --git a/media/java/android/media/tv/extension/signal/IAudioSignalInfo.aidl b/media/java/android/media/tv/extension/signal/IAudioSignalInfo.aidl new file mode 100644 index 000000000000..4c953a08364a --- /dev/null +++ b/media/java/android/media/tv/extension/signal/IAudioSignalInfo.aidl @@ -0,0 +1,36 @@ +/* + * 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 android.media.tv.extension.signal; + +import android.media.tv.extension.signal.IAudioSignalInfoListener; +import android.os.Bundle; + +/** + * @hide + */ +interface IAudioSignalInfo { + // Get audio signal information. + Bundle getAudioSignalInfo(String sessionToken); + // Notify TIS whether user selects audio track via mts button on the remote control. + void notifyMtsSelectTrackFlag(boolean mtsFlag); + // Get the audio track id selected via mts. + String getMtsSelectedTrackId(); + // Register a listener to receive the updated audio signal information. + void addAudioSignalInfoListener(String clientToken, in IAudioSignalInfoListener listener); + // Remove a listener for audio signal information update notifications. + void removeAudioSignalInfoListener(in IAudioSignalInfoListener listener); +} diff --git a/media/java/android/media/tv/extension/signal/IAudioSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/IAudioSignalInfoListener.aidl new file mode 100644 index 000000000000..adf239ab1b32 --- /dev/null +++ b/media/java/android/media/tv/extension/signal/IAudioSignalInfoListener.aidl @@ -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 android.media.tv.extension.signal; + +import android.os.Bundle; + +/** + * @hide + */ +oneway interface IAudioSignalInfoListener { + void onAudioSignalInfoChanged(String sessionToken, in Bundle changedSignalInfo); +} diff --git a/media/java/android/media/tv/extension/signal/IHdmiSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/IHdmiSignalInfoListener.aidl new file mode 100644 index 000000000000..bd468b2e7f34 --- /dev/null +++ b/media/java/android/media/tv/extension/signal/IHdmiSignalInfoListener.aidl @@ -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 android.media.tv.extension.signal; + +/** + * @hide + */ +oneway interface IHdmiSignalInfoListener { + void onSignalInfoChanged(String sessionToken); + void onLowLatencyModeChanged(int enable); +} diff --git a/media/java/android/media/tv/extension/signal/IHdmiSignalInterface.aidl b/media/java/android/media/tv/extension/signal/IHdmiSignalInterface.aidl new file mode 100644 index 000000000000..39625e3c958d --- /dev/null +++ b/media/java/android/media/tv/extension/signal/IHdmiSignalInterface.aidl @@ -0,0 +1,36 @@ +/* + * 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 android.media.tv.extension.signal; + +import android.media.tv.extension.signal.IHdmiSignalInfoListener; +import android.os.Bundle; + +/** + * @hide + */ +interface IHdmiSignalInterface { + // Register a listener for Hdmi Signal Info updates. + void addHdmiSignalInfoListener(String inputId, in IHdmiSignalInfoListener listener); + // Remove a listener for Hdmi Signal Info update notifications. + void removeHdmiSignalInfoListener(String inputId, in IHdmiSignalInfoListener listener); + // Obtain HdmiSignalInfo based on the inputId and sessionToken. + Bundle getHdmiSignalInfo(String sessionToken); + // Enable/disable low-latency decoding mode. + void setLowLatency(String sessionToken, int mode); + // Enable/disable force-VRR mode. + void setForceVrr(String sessionToken, int mode); +} diff --git a/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoInterface.aidl b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoInterface.aidl new file mode 100644 index 000000000000..7f05e7033aeb --- /dev/null +++ b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoInterface.aidl @@ -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 android.media.tv.extension.signal; + +import android.media.tv.extension.signal.ITunerFrontendSignalInfoListener; +import android.os.Bundle; + +/** +* @hide +*/ +interface ITunerFrontendSignalInfoInterface { + Bundle getFrontendSignalInfo(String sessionToken); + void setFrontendSignalInfoListener(in ITunerFrontendSignalInfoListener listener); +} diff --git a/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoListener.aidl new file mode 100644 index 000000000000..9c22a3570cce --- /dev/null +++ b/media/java/android/media/tv/extension/signal/ITunerFrontendSignalInfoListener.aidl @@ -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 android.media.tv.extension.signal; + +/** +* @hide +*/ +oneway interface ITunerFrontendSignalInfoListener { + void onFrontendStatusChanged(int frontendStatus); +} diff --git a/media/java/android/media/tv/extension/signal/IVideoSignalInfo.aidl b/media/java/android/media/tv/extension/signal/IVideoSignalInfo.aidl new file mode 100644 index 000000000000..b17142acf2ab --- /dev/null +++ b/media/java/android/media/tv/extension/signal/IVideoSignalInfo.aidl @@ -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 android.media.tv.extension.signal; + +import android.media.tv.extension.signal.IVideoSignalInfoListener; +import android.os.Bundle; + + +/** + * @hide + */ +interface IVideoSignalInfo { + void addVideoSignalInfoListener(String clientToken, in IVideoSignalInfoListener listener); + void removeVideoSignalInfoListener(in IVideoSignalInfoListener listener); + Bundle getVideoSignalInfo(String sessionToken); +} diff --git a/media/java/android/media/tv/extension/signal/IVideoSignalInfoListener.aidl b/media/java/android/media/tv/extension/signal/IVideoSignalInfoListener.aidl new file mode 100644 index 000000000000..aafc192f32fa --- /dev/null +++ b/media/java/android/media/tv/extension/signal/IVideoSignalInfoListener.aidl @@ -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 android.media.tv.extension.signal; + +import android.os.Bundle; + +/** + * @hide + */ +oneway interface IVideoSignalInfoListener { + void onVideoSignalInfoChanged(String sessionToken, in Bundle changedSignalInfo); +} diff --git a/media/java/android/media/tv/extension/time/IBroadcastTime.aidl b/media/java/android/media/tv/extension/time/IBroadcastTime.aidl new file mode 100644 index 000000000000..123d00f9faf4 --- /dev/null +++ b/media/java/android/media/tv/extension/time/IBroadcastTime.aidl @@ -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 android.media.tv.extension.time; + +import android.os.Bundle; + +/** + * @hide + */ +interface IBroadcastTime { + long getUtcTime(); + long getLocalTime(); + Bundle getTimeZoneInfo(); + long getUtcTimePerStream(String SessionToken); + long getLocalTimePerStream(String SessionToken); +}
\ No newline at end of file diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig index 64416525441b..4b832aee49c5 100644 --- a/media/java/android/media/tv/flags/media_tv.aconfig +++ b/media/java/android/media/tv/flags/media_tv.aconfig @@ -2,6 +2,22 @@ package: "android.media.tv.flags" container: "system" flag { + name: "enable_le_audio_broadcast_ui" + is_exported: true + namespace: "media_tv" + description: "Enable Broadcast UI for LE Audio on TV." + bug: "378732734" +} + +flag { + name: "enable_le_audio_unicast_ui" + is_exported: true + namespace: "media_tv" + description: "Enable Unicast UI for LE Audio on TV." + bug: "378732734" +} + +flag { name: "broadcast_visibility_types" is_exported: true namespace: "media_tv" @@ -77,11 +93,19 @@ flag { name: "set_resource_holder_retain" is_exported: true namespace: "media_tv" - description : "Feature flag to add setResourceHolderRetain api to MediaCas and Tuner JAVA." + description: "Feature flag to add setResourceHolderRetain api to MediaCas and Tuner JAVA." bug: "372973197" } flag { + name: "mediacas_update_client_profile_priority" + is_exported: true + namespace: "media_tv" + description: "Feature flag to add updateResourcePriority api to MediaCas" + bug: "372971241" +} + +flag { name: "apply_picture_profiles" is_exported: true namespace: "media_tv" diff --git a/media/java/android/media/tv/interactive/TvInteractiveAppView.java b/media/java/android/media/tv/interactive/TvInteractiveAppView.java index 635572d12cc5..9e9699ff6bc6 100644 --- a/media/java/android/media/tv/interactive/TvInteractiveAppView.java +++ b/media/java/android/media/tv/interactive/TvInteractiveAppView.java @@ -271,6 +271,38 @@ public class TvInteractiveAppView extends ViewGroup { } } + /** + * Controls whether the TvInteractiveAppView's surface is placed on top of other regular surface + * views in the window (but still behind the window itself). + * + * <p>Calling this overrides any previous call to {@link #setZOrderOnTop}. + * + * @param isMediaOverlay {@code true} to be on top of another regular surface, {@code false} + * otherwise. + */ + @FlaggedApi(Flags.FLAG_TIAF_V_APIS) + public void setZOrderMediaOverlay(boolean isMediaOverlay) { + if (mSurfaceView != null) { + mSurfaceView.setZOrderOnTop(false); + mSurfaceView.setZOrderMediaOverlay(isMediaOverlay); + } + } + + /** + * Controls whether the TvInterActiveAppView's surface is placed on top of its window. + * + * <p>Calling this overrides any previous call to {@link #setZOrderMediaOverlay}. + * + * @param onTop {@code true} to be on top of its window, {@code false} otherwise. + */ + @FlaggedApi(Flags.FLAG_TIAF_V_APIS) + public void setZOrderOnTop(boolean onTop) { + if (mSurfaceView != null) { + mSurfaceView.setZOrderMediaOverlay(false); + mSurfaceView.setZOrderOnTop(onTop); + } + } + private void resetSurfaceView() { if (mSurfaceView != null) { mSurfaceView.getHolder().removeCallback(mSurfaceHolderCallback); diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index d05ee551c172..a94230014437 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -1362,13 +1362,26 @@ static jboolean android_media_MediaPlayer_setOutputDevice(JNIEnv *env, jobject t return mp->setOutputDevice(device_id) == NO_ERROR; } -static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz) +static jintArray android_media_MediaPlayer_getRoutedDeviceIds(JNIEnv *env, jobject thiz) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); if (mp == NULL) { - return AUDIO_PORT_HANDLE_NONE; + return NULL; + } + DeviceIdVector deviceIds; + // TODO: b/379161379 - Should we throw an exception if the result is not ok? + mp->getRoutedDeviceIds(deviceIds); + jintArray result; + result = env->NewIntArray(deviceIds.size()); + if (result == NULL) { + return NULL; } - return mp->getRoutedDeviceId(); + jint* values = env->GetIntArrayElements(result, 0); + for (unsigned int i = 0; i < deviceIds.size(); i++) { + values[i++] = static_cast<jint>(deviceIds[i]); + } + env->ReleaseIntArrayElements(result, values, 0); + return result; } static void android_media_MediaPlayer_enableDeviceCallback( @@ -1452,7 +1465,8 @@ static const JNINativeMethod gMethods[] = { // AudioRouting {"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer_setOutputDevice}, - {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer_getRoutedDeviceId}, + {"native_getRoutedDeviceIds", "()[I", + (void *)android_media_MediaPlayer_getRoutedDeviceIds}, {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer_enableDeviceCallback}, }; diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index 9a6d5d7d730a..643fc8a2d925 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -722,21 +722,31 @@ android_media_MediaRecorder_setInputDevice(JNIEnv *env, jobject thiz, jint devic return true; } -static jint -android_media_MediaRecorder_getRoutedDeviceId(JNIEnv *env, jobject thiz) +static jintArray +android_media_MediaRecorder_getRoutedDeviceIds(JNIEnv *env, jobject thiz) { - ALOGV("android_media_MediaRecorder_getRoutedDeviceId"); + ALOGV("android_media_MediaRecorder_getRoutedDeviceIds"); sp<MediaRecorder> mr = getMediaRecorder(env, thiz); if (mr == NULL) { jniThrowException(env, "java/lang/IllegalStateException", NULL); - return AUDIO_PORT_HANDLE_NONE; + return NULL; } - audio_port_handle_t deviceId; - process_media_recorder_call(env, mr->getRoutedDeviceId(&deviceId), - "java/lang/RuntimeException", "getRoutedDeviceId failed."); - return (jint) deviceId; + DeviceIdVector deviceIds; + process_media_recorder_call(env, mr->getRoutedDeviceIds(deviceIds), + "java/lang/RuntimeException", "getRoutedDeviceIds failed."); + jintArray result; + result = env->NewIntArray(deviceIds.size()); + if (result == NULL) { + return NULL; + } + jint* values = env->GetIntArrayElements(result, 0); + for (unsigned int i = 0; i < deviceIds.size(); i++) { + values[i++] = static_cast<jint>(deviceIds[i]); + } + env->ReleaseIntArrayElements(result, values, 0); + return result; } static void @@ -880,7 +890,8 @@ static const JNINativeMethod gMethods[] = { {"native_getMetrics", "()Landroid/os/PersistableBundle;", (void *)android_media_MediaRecorder_native_getMetrics}, {"native_setInputDevice", "(I)Z", (void *)android_media_MediaRecorder_setInputDevice}, - {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaRecorder_getRoutedDeviceId}, + {"native_getRoutedDeviceIds", "()[I", + (void *)android_media_MediaRecorder_getRoutedDeviceIds}, {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaRecorder_enableDeviceCallback}, {"native_getActiveMicrophones", "(Ljava/util/ArrayList;)I", (void *)android_media_MediaRecord_getActiveMicrophones}, diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java index ac85ab7f6a6e..88c1c434cc0d 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java @@ -257,6 +257,16 @@ public class CameraBinderTest extends AndroidTestCase { public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) { // TODO Auto-generated method stub } + + /* + * (non-Javadoc) + * @see android.hardware.camera2.ICameraDeviceCallbacks#onClientSharedAccessPriorityChanged + */ + @Override + public void onClientSharedAccessPriorityChanged(boolean primaryClient) { + // TODO Auto-generated method stub + } + } @SmallTest @@ -276,7 +286,7 @@ public class CameraBinderTest extends AndroidTestCase { 0 /*oomScoreOffset*/, getContext().getApplicationInfo().targetSdkVersion, ICameraService.ROTATION_OVERRIDE_NONE, clientAttribution, - DEVICE_POLICY_DEFAULT); + DEVICE_POLICY_DEFAULT, false/*sharedMode*/); assertNotNull(String.format("Camera %s was null", cameraId), cameraUser); Log.v(TAG, String.format("Camera %s connected", cameraId)); @@ -320,6 +330,13 @@ public class CameraBinderTest extends AndroidTestCase { Log.v(TAG, String.format("Camera " + cameraId + " torch strength level changed to " + torchStrength )); } + @Override + public void onCameraOpenedInSharedMode(String cameraId, String clientPackageName, + int deviceId, boolean primaryClient) { + Log.v(TAG, "Camera " + cameraId + " is opened in shared mode by " + + "client package " + clientPackageName + " as primary client=" + + primaryClient); + } } /** diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java index 35ad924cee74..3758c515c1a5 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java @@ -175,6 +175,15 @@ public class CameraDeviceBinderTest extends AndroidTestCase { public void onRepeatingRequestError(long lastFrameNumber, int repeatingRequestId) { // TODO Auto-generated method stub } + + /** + * (non-Javadoc) + * @see android.hardware.camera2.ICameraDeviceCallbacks#onClientSharedAccessPriorityChanged + */ + @Override + public void onClientSharedAccessPriorityChanged(boolean primaryClient) { + // TODO Auto-generated method stub + } } class IsMetadataNotEmpty implements ArgumentMatcher<CameraMetadataNative> { @@ -250,7 +259,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase { mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId, /*oomScoreOffset*/0, getContext().getApplicationInfo().targetSdkVersion, - ICameraService.ROTATION_OVERRIDE_NONE, clientAttribution, DEVICE_POLICY_DEFAULT); + ICameraService.ROTATION_OVERRIDE_NONE, clientAttribution, DEVICE_POLICY_DEFAULT, + /*sharedMode*/false); assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser); mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index a0460572abfc..2d1fbf9e7f66 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -361,6 +361,8 @@ LIBANDROID { APerformanceHint_setThreads; # introduced=UpsideDownCake APerformanceHint_setPreferPowerEfficiency; # introduced=VanillaIceCream APerformanceHint_reportActualWorkDuration2; # introduced=VanillaIceCream + APerformanceHint_notifyWorkloadIncrease; # introduced=36 + APerformanceHint_notifyWorkloadReset; # introduced=36 AWorkDuration_create; # introduced=VanillaIceCream AWorkDuration_release; # introduced=VanillaIceCream AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream @@ -379,6 +381,8 @@ LIBANDROID_PLATFORM { APerformanceHint_getThreadIds; APerformanceHint_createSessionInternal; APerformanceHint_setUseFMQForTesting; + APerformanceHint_getRateLimiterPropertiesForTesting; + APerformanceHint_setUseNewLoadHintBehaviorForTesting; extern "C++" { ASurfaceControl_registerSurfaceStatsListener*; ASurfaceControl_unregisterSurfaceStatsListener*; diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp index 15f77cebf3ba..e2fa94dd39bb 100644 --- a/native/android/performance_hint.cpp +++ b/native/android/performance_hint.cpp @@ -33,12 +33,14 @@ #include <android/performance_hint.h> #include <android/trace.h> #include <android_os.h> +#include <cutils/trace.h> #include <fmq/AidlMessageQueue.h> #include <inttypes.h> #include <performance_hint_private.h> #include <utils/SystemClock.h> #include <chrono> +#include <format> #include <future> #include <set> #include <utility> @@ -63,6 +65,22 @@ struct APerformanceHintSession; constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count(); struct AWorkDuration : public hal::WorkDuration {}; +// A pair of values that determine the behavior of the +// load hint rate limiter, to only allow "X hints every Y seconds" +constexpr double kLoadHintInterval = std::chrono::nanoseconds(2s).count(); +constexpr double kMaxLoadHintsPerInterval = 20; +constexpr double kReplenishRate = kMaxLoadHintsPerInterval / kLoadHintInterval; +bool kForceNewHintBehavior = false; + +template <class T> +constexpr int32_t enum_size() { + return static_cast<int32_t>(*(ndk::enum_range<T>().end() - 1)) + 1; +} + +bool useNewLoadHintBehavior() { + return android::os::adpf_use_load_hints() || kForceNewHintBehavior; +} + // Shared lock for the whole PerformanceHintManager and sessions static std::mutex sHintMutex = std::mutex{}; class FMQWrapper { @@ -76,7 +94,8 @@ public: hal::WorkDuration* durations, size_t count) REQUIRES(sHintMutex); bool updateTargetWorkDuration(std::optional<hal::SessionConfig>& config, int64_t targetDurationNanos) REQUIRES(sHintMutex); - bool sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) REQUIRES(sHintMutex); + bool sendHints(std::optional<hal::SessionConfig>& config, std::vector<hal::SessionHint>& hint, + int64_t now) REQUIRES(sHintMutex); bool setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode, bool enabled) REQUIRES(sHintMutex); void setToken(ndk::SpAIBinder& token); @@ -86,10 +105,11 @@ public: private: template <HalChannelMessageContents::Tag T, bool urgent = false, class C = HalChannelMessageContents::_at<T>> - bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1) - REQUIRES(sHintMutex); + bool sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count = 1, + int64_t now = ::android::uptimeNanos()) REQUIRES(sHintMutex); template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>> - void writeBuffer(C* message, hal::SessionConfig& config, size_t count) REQUIRES(sHintMutex); + void writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) + REQUIRES(sHintMutex); bool isActiveLocked() REQUIRES(sHintMutex); bool updatePersistentTransaction() REQUIRES(sHintMutex); @@ -120,6 +140,7 @@ public: hal::SessionTag tag = hal::SessionTag::APP); int64_t getPreferredRateNanos() const; FMQWrapper& getFMQWrapper(); + bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex); private: // Necessary to create an empty binder object @@ -138,6 +159,8 @@ private: ndk::SpAIBinder mToken; const int64_t mPreferredRateNanos; FMQWrapper mFMQWrapper; + double mHintBudget = kMaxLoadHintsPerInterval; + int64_t mLastBudgetReplenish = 0; }; struct APerformanceHintSession { @@ -151,7 +174,9 @@ public: int updateTargetWorkDuration(int64_t targetDurationNanos); int reportActualWorkDuration(int64_t actualDurationNanos); - int sendHint(SessionHint hint); + int sendHints(std::vector<hal::SessionHint>& hints, int64_t now, const char* debugName); + int notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName); + int notifyWorkloadReset(bool cpu, bool gpu, const char* debugName); int setThreads(const int32_t* threadIds, size_t size); int getThreadIds(int32_t* const threadIds, size_t* size); int setPreferPowerEfficiency(bool enabled); @@ -173,6 +198,8 @@ private: // Last target hit timestamp int64_t mLastTargetMetTimestamp GUARDED_BY(sHintMutex); // Last hint reported from sendHint indexed by hint value + // This is only used by the old rate limiter impl and is replaced + // with the new rate limiter under a flag std::vector<int64_t> mLastHintSentTimestamp GUARDED_BY(sHintMutex); // Cached samples std::vector<hal::WorkDuration> mActualWorkDurations GUARDED_BY(sHintMutex); @@ -255,6 +282,21 @@ APerformanceHintManager* APerformanceHintManager::create(std::shared_ptr<IHintMa return new APerformanceHintManager(manager, preferredRateNanos); } +bool APerformanceHintManager::canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) { + mHintBudget = + std::max(kMaxLoadHintsPerInterval, + mHintBudget + + static_cast<double>(now - mLastBudgetReplenish) * kReplenishRate); + mLastBudgetReplenish = now; + + // If this youngest timestamp isn't older than the timeout time, we can't send + if (hints.size() > mHintBudget) { + return false; + } + mHintBudget -= hints.size(); + return true; +} + APerformanceHintSession* APerformanceHintManager::createSession( const int32_t* threadIds, size_t size, int64_t initialTargetWorkDurationNanos, hal::SessionTag tag) { @@ -292,9 +334,7 @@ FMQWrapper& APerformanceHintManager::getFMQWrapper() { // ===================================== APerformanceHintSession implementation -constexpr int kNumEnums = - ndk::enum_range<hal::SessionHint>().end() - ndk::enum_range<hal::SessionHint>().begin(); - +constexpr int kNumEnums = enum_size<hal::SessionHint>(); APerformanceHintSession::APerformanceHintSession(std::shared_ptr<IHintManager> hintManager, std::shared_ptr<IHintSession> session, int64_t preferredRateNanos, @@ -361,31 +401,83 @@ int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNano return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration)); } -int APerformanceHintSession::sendHint(SessionHint hint) { +int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now, + const char*) { std::scoped_lock lock(sHintMutex); - if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) { - ALOGE("%s: invalid session hint %d", __FUNCTION__, hint); + if (hints.empty()) { return EINVAL; } - int64_t now = uptimeNanos(); + for (auto&& hint : hints) { + if (static_cast<int32_t>(hint) < 0 || static_cast<int32_t>(hint) >= kNumEnums) { + ALOGE("%s: invalid session hint %d", __FUNCTION__, hint); + return EINVAL; + } + } - // Limit sendHint to a pre-detemined rate for safety - if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) { - return 0; + if (useNewLoadHintBehavior()) { + if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) { + return EBUSY; + } + } + // keep old rate limiter behavior for legacy flag + else { + for (auto&& hint : hints) { + if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + SEND_HINT_TIMEOUT)) { + return EBUSY; + } + } } - if (!getFMQ().sendHint(mSessionConfig, hint)) { - ndk::ScopedAStatus ret = mHintSession->sendHint(hint); + if (!getFMQ().sendHints(mSessionConfig, hints, now)) { + for (auto&& hint : hints) { + ndk::ScopedAStatus ret = mHintSession->sendHint(static_cast<int32_t>(hint)); - if (!ret.isOk()) { - ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage()); - return EPIPE; + if (!ret.isOk()) { + ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.getMessage()); + return EPIPE; + } + } + } + + if (!useNewLoadHintBehavior()) { + for (auto&& hint : hints) { + mLastHintSentTimestamp[static_cast<int32_t>(hint)] = now; } } - mLastHintSentTimestamp[hint] = now; + + if (ATrace_isEnabled()) { + ATRACE_INSTANT("Sending load hint"); + } + return 0; } +int APerformanceHintSession::notifyWorkloadIncrease(bool cpu, bool gpu, const char* debugName) { + std::vector<hal::SessionHint> hints(2); + hints.clear(); + if (cpu) { + hints.push_back(hal::SessionHint::CPU_LOAD_UP); + } + if (gpu) { + hints.push_back(hal::SessionHint::GPU_LOAD_UP); + } + int64_t now = ::android::uptimeNanos(); + return sendHints(hints, now, debugName); +} + +int APerformanceHintSession::notifyWorkloadReset(bool cpu, bool gpu, const char* debugName) { + std::vector<hal::SessionHint> hints(2); + hints.clear(); + if (cpu) { + hints.push_back(hal::SessionHint::CPU_LOAD_RESET); + } + if (gpu) { + hints.push_back(hal::SessionHint::GPU_LOAD_RESET); + } + int64_t now = ::android::uptimeNanos(); + return sendHints(hints, now, debugName); +} + int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) { if (size == 0) { ALOGE("%s: the list of thread ids must not be empty.", __FUNCTION__); @@ -565,24 +657,25 @@ void FMQWrapper::stopChannel(IHintManager* manager) { } template <HalChannelMessageContents::Tag T, class C> -void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t) { - new (mFmqTransaction.getSlot(0)) hal::ChannelMessage{ - .sessionID = static_cast<int32_t>(config.id), - .timeStampNanos = ::android::uptimeNanos(), - .data = HalChannelMessageContents::make<T, C>(std::move(*message)), - }; +void FMQWrapper::writeBuffer(C* message, hal::SessionConfig& config, size_t count, int64_t now) { + for (size_t i = 0; i < count; ++i) { + new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{ + .sessionID = static_cast<int32_t>(config.id), + .timeStampNanos = now, + .data = HalChannelMessageContents::make<T, C>(std::move(*(message + i))), + }; + } } template <> void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkDuration* messages, hal::SessionConfig& config, - size_t count) { + size_t count, int64_t now) { for (size_t i = 0; i < count; ++i) { hal::WorkDuration& message = messages[i]; new (mFmqTransaction.getSlot(i)) hal::ChannelMessage{ .sessionID = static_cast<int32_t>(config.id), - .timeStampNanos = - (i == count - 1) ? ::android::uptimeNanos() : message.timeStampNanos, + .timeStampNanos = (i == count - 1) ? now : message.timeStampNanos, .data = HalChannelMessageContents::make<HalChannelMessageContents::workDuration, hal::WorkDurationFixedV1>({ .durationNanos = message.cpuDurationNanos, @@ -595,7 +688,8 @@ void FMQWrapper::writeBuffer<HalChannelMessageContents::workDuration>(hal::WorkD } template <HalChannelMessageContents::Tag T, bool urgent, class C> -bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count) { +bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* message, size_t count, + int64_t now) { if (!isActiveLocked() || !config.has_value() || mCorrupted) { return false; } @@ -609,7 +703,7 @@ bool FMQWrapper::sendMessages(std::optional<hal::SessionConfig>& config, C* mess return false; } } - writeBuffer<T, C>(message, *config, count); + writeBuffer<T, C>(message, *config, count, now); mQueue->commitWrite(count); mEventFlag->wake(mWriteMask); // Re-create the persistent transaction after writing @@ -641,10 +735,9 @@ bool FMQWrapper::updateTargetWorkDuration(std::optional<hal::SessionConfig>& con return sendMessages<HalChannelMessageContents::targetDuration>(config, &targetDurationNanos); } -bool FMQWrapper::sendHint(std::optional<hal::SessionConfig>& config, SessionHint hint) { - return sendMessages<HalChannelMessageContents::hint>(config, - reinterpret_cast<hal::SessionHint*>( - &hint)); +bool FMQWrapper::sendHints(std::optional<hal::SessionConfig>& config, + std::vector<hal::SessionHint>& hints, int64_t now) { + return sendMessages<HalChannelMessageContents::hint>(config, hints.data(), hints.size(), now); } bool FMQWrapper::setMode(std::optional<hal::SessionConfig>& config, hal::SessionMode mode, @@ -758,7 +851,9 @@ void APerformanceHint_closeSession(APerformanceHintSession* session) { int APerformanceHint_sendHint(APerformanceHintSession* session, SessionHint hint) { VALIDATE_PTR(session) - return session->sendHint(hint); + std::vector<hal::SessionHint> hints{static_cast<hal::SessionHint>(hint)}; + int64_t now = ::android::uptimeNanos(); + return session->sendHints(hints, now, "HWUI hint"); } int APerformanceHint_setThreads(APerformanceHintSession* session, const pid_t* threadIds, @@ -791,6 +886,26 @@ int APerformanceHint_reportActualWorkDuration2(APerformanceHintSession* session, return session->reportActualWorkDuration(workDurationPtr); } +int APerformanceHint_notifyWorkloadIncrease(APerformanceHintSession* session, bool cpu, bool gpu, + const char* debugName) { + VALIDATE_PTR(session) + VALIDATE_PTR(debugName) + if (!useNewLoadHintBehavior()) { + return ENOTSUP; + } + return session->notifyWorkloadIncrease(cpu, gpu, debugName); +} + +int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool cpu, bool gpu, + const char* debugName) { + VALIDATE_PTR(session) + VALIDATE_PTR(debugName) + if (!useNewLoadHintBehavior()) { + return ENOTSUP; + } + return session->notifyWorkloadReset(cpu, gpu, debugName); +} + AWorkDuration* AWorkDuration_create() { return new AWorkDuration(); } @@ -838,3 +953,13 @@ void APerformanceHint_setIHintManagerForTesting(void* iManager) { void APerformanceHint_setUseFMQForTesting(bool enabled) { gForceFMQEnabled = enabled; } + +void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval, + int64_t* loadHintInterval) { + *maxLoadHintsPerInterval = kMaxLoadHintsPerInterval; + *loadHintInterval = kLoadHintInterval; +} + +void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) { + kForceNewHintBehavior = newBehavior; +} diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp index 9de3a6f525e6..f707a0e9b0b2 100644 --- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp @@ -66,6 +66,18 @@ public: std::optional<hal::ChannelConfig>* _aidl_return), (override)); MOCK_METHOD(ScopedAStatus, closeSessionChannel, (), (override)); + MOCK_METHOD(ScopedAStatus, getCpuHeadroom, + (const ::aidl::android::os::CpuHeadroomParamsInternal& in_params, + std::vector<float>* _aidl_return), + (override)); + MOCK_METHOD(ScopedAStatus, getCpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), + (override)); + MOCK_METHOD(ScopedAStatus, getGpuHeadroom, + (const ::aidl::android::os::GpuHeadroomParamsInternal& in_params, + float* _aidl_return), + (override)); + MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), + (override)); MOCK_METHOD(SpAIBinder, asBinder, (), (override)); MOCK_METHOD(bool, isRemote, (), (override)); }; @@ -90,7 +102,10 @@ class PerformanceHintTest : public Test { public: void SetUp() override { mMockIHintManager = ndk::SharedRefBase::make<NiceMock<MockIHintManager>>(); + APerformanceHint_getRateLimiterPropertiesForTesting(&mMaxLoadHintsPerInterval, + &mLoadHintInterval); APerformanceHint_setIHintManagerForTesting(&mMockIHintManager); + APerformanceHint_setUseNewLoadHintBehaviorForTesting(true); } void TearDown() override { @@ -176,6 +191,9 @@ public: int kMockQueueSize = 20; bool mUsingFMQ = false; + int32_t mMaxLoadHintsPerInterval; + int64_t mLoadHintInterval; + template <HalChannelMessageContents::Tag T, class C = HalChannelMessageContents::_at<T>> void expectToReadFromFmq(C expected) { hal::ChannelMessage readData; @@ -218,7 +236,6 @@ TEST_F(PerformanceHintTest, TestSession) { EXPECT_CALL(*mMockSession, reportActualWorkDuration2(_)).Times(Exactly(1)); result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos); EXPECT_EQ(0, result); - result = APerformanceHint_updateTargetWorkDuration(session, -1L); EXPECT_EQ(EINVAL, result); result = APerformanceHint_reportActualWorkDuration(session, -1L); @@ -228,18 +245,28 @@ TEST_F(PerformanceHintTest, TestSession) { EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1)); result = APerformanceHint_sendHint(session, hintId); EXPECT_EQ(0, result); - usleep(110000); // Sleep for longer than the update timeout. - EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1)); - result = APerformanceHint_sendHint(session, hintId); + EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_UP))).Times(Exactly(1)); + result = APerformanceHint_notifyWorkloadIncrease(session, true, false, "Test hint"); EXPECT_EQ(0, result); - // Expect to get rate limited if we try to send faster than the limiter allows - EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(0)); - result = APerformanceHint_sendHint(session, hintId); + EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_RESET))).Times(Exactly(1)); + EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::GPU_LOAD_RESET))).Times(Exactly(1)); + result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint"); EXPECT_EQ(0, result); result = APerformanceHint_sendHint(session, static_cast<SessionHint>(-1)); EXPECT_EQ(EINVAL, result); + Mock::VerifyAndClearExpectations(mMockSession.get()); + for (int i = 0; i < mMaxLoadHintsPerInterval; ++i) { + APerformanceHint_sendHint(session, hintId); + } + + // Expect to get rate limited if we try to send faster than the limiter allows + EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0)); + result = APerformanceHint_notifyWorkloadIncrease(session, true, true, "Test hint"); + EXPECT_EQ(result, EBUSY); + EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0)); + result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint"); EXPECT_CALL(*mMockSession, close()).Times(Exactly(1)); APerformanceHint_closeSession(session); } diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp index 23dd9b7aee37..4180710534c3 100644 --- a/native/graphics/jni/Android.bp +++ b/native/graphics/jni/Android.bp @@ -45,8 +45,10 @@ cc_library_shared { header_libs: [ "jni_headers", + "native_headers", "libhwui_internal_headers", ], + export_header_lib_headers: ["native_headers"], static_libs: [ "libarect", diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt index c25f77b12116..f587660cae5b 100644 --- a/nfc/api/system-current.txt +++ b/nfc/api/system-current.txt @@ -57,6 +57,7 @@ package android.nfc { @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension { method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference(); + method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int forceRoutingTableCommit(); method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.List<java.lang.String> getActiveNfceeList(); method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.nfc.RoutingStatus getRoutingStatus(); method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.List<android.nfc.NfcRoutingTableEntry> getRoutingTable(); @@ -73,6 +74,9 @@ package android.nfc { method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void triggerInitialization(); method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback); + field public static final int COMMIT_ROUTING_STATUS_FAILED = 3; // 0x3 + field public static final int COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS = 6; // 0x6 + field public static final int COMMIT_ROUTING_STATUS_OK = 0; // 0x0 field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int DISABLE = 0; // 0x0 field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_DEFAULT = 1; // 0x1 field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_EE = 3; // 0x3 @@ -89,13 +93,14 @@ package android.nfc { method public void onBootFinished(int); method public void onBootStarted(); method public void onCardEmulationActivated(boolean); - method public void onDisable(@NonNull java.util.function.Consumer<java.lang.Boolean>); method public void onDisableFinished(int); + method public void onDisableRequested(@NonNull java.util.function.Consumer<java.lang.Boolean>); method public void onDisableStarted(); method public void onEeListenActivated(boolean); - method public void onEnable(@NonNull java.util.function.Consumer<java.lang.Boolean>); method public void onEnableFinished(int); + method public void onEnableRequested(@NonNull java.util.function.Consumer<java.lang.Boolean>); method public void onEnableStarted(); + method public void onExtractOemPackages(@NonNull android.nfc.NdefMessage, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>); method public void onGetOemAppSearchIntent(@NonNull java.util.List<java.lang.String>, @NonNull java.util.function.Consumer<android.content.Intent>); method public void onHceEventReceived(int); method public void onLaunchHceAppChooserActivity(@NonNull String, @NonNull java.util.List<android.nfc.cardemulation.ApduServiceInfo>, @NonNull android.content.ComponentName, @NonNull String); @@ -106,7 +111,7 @@ package android.nfc { method public void onReaderOptionChanged(boolean); method public void onRfDiscoveryStarted(boolean); method public void onRfFieldActivated(boolean); - method public void onRoutingChanged(); + method public void onRoutingChanged(@NonNull java.util.function.Consumer<java.lang.Boolean>); method public void onRoutingTableFull(); method public void onStateUpdated(int); method public void onTagConnected(boolean); @@ -183,6 +188,12 @@ package android.nfc.cardemulation { method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int); method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void overrideRoutingTable(@NonNull android.app.Activity, int, int); method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public void recoverRoutingTable(@NonNull android.app.Activity); + method @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setServiceEnabledForCategoryOther(@NonNull android.content.ComponentName, boolean); + field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3; // 0x3 + field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1; // 0x1 + field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2; // 0x2 + field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4; // 0x4 + field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_OK = 0; // 0x0 } } diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl index 40fd0683f465..31514a09adad 100644 --- a/nfc/java/android/nfc/INfcAdapter.aidl +++ b/nfc/java/android/nfc/INfcAdapter.aidl @@ -120,4 +120,5 @@ interface INfcAdapter boolean isTagPresent(); List<Entry> getRoutingTableEntryList(); void indicateDataMigration(boolean inProgress, String pkg); + int commitRouting(); } diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl index 5e2e92d958a4..633d8bfbbb67 100644 --- a/nfc/java/android/nfc/INfcCardEmulation.aidl +++ b/nfc/java/android/nfc/INfcCardEmulation.aidl @@ -47,7 +47,7 @@ interface INfcCardEmulation boolean unsetPreferredService(); boolean supportsAidPrefixRegistration(); ApduServiceInfo getPreferredPaymentService(int userHandle); - boolean setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status); + int setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status); boolean isDefaultPaymentRegistered(); void overrideRoutingTable(int userHandle, String protocol, String technology, in String pkg); diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl index fb793b024288..1a21c0bae413 100644 --- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl +++ b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl @@ -41,7 +41,7 @@ interface INfcOemExtensionCallback { void onEnableFinished(int status); void onDisableFinished(int status); void onTagDispatch(in ResultReceiver isSkipped); - void onRoutingChanged(); + void onRoutingChanged(in ResultReceiver isSkipped); void onHceEventReceived(int action); void onReaderOptionChanged(boolean enabled); void onCardEmulationActivated(boolean isActivated); @@ -54,4 +54,5 @@ interface INfcOemExtensionCallback { void onLaunchHceTapAgainActivity(in ApduServiceInfo service, in String category); void onRoutingTableFull(); void onLogEventNotified(in OemLogItems item); + void onExtractOemPackages(in NdefMessage message, in ResultReceiver packageReceiver); } diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java index 57ee981caf9c..326ca6449c53 100644 --- a/nfc/java/android/nfc/NfcOemExtension.java +++ b/nfc/java/android/nfc/NfcOemExtension.java @@ -23,11 +23,11 @@ import static android.nfc.cardemulation.CardEmulation.routeIntToString; import android.Manifest; import android.annotation.CallbackExecutor; +import android.annotation.DurationMillisLong; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.content.ComponentName; import android.content.Context; @@ -194,6 +194,30 @@ public final class NfcOemExtension { public @interface StatusCode {} /** + * Routing commit succeeded. + */ + public static final int COMMIT_ROUTING_STATUS_OK = 0; + /** + * Routing commit failed. + */ + public static final int COMMIT_ROUTING_STATUS_FAILED = 3; + /** + * Routing commit failed due to the update is in progress. + */ + public static final int COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS = 6; + + /** + * Status codes returned when calling {@link #forceRoutingTableCommit()} + * @hide + */ + @IntDef(prefix = "COMMIT_ROUTING_STATUS_", value = { + COMMIT_ROUTING_STATUS_OK, + COMMIT_ROUTING_STATUS_FAILED, + COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CommitRoutingStatusCode {} + /** * Interface for Oem extensions for NFC. */ public interface Callback { @@ -233,8 +257,7 @@ public final class NfcOemExtension { * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}. * false if NFC cannot be enabled at this time. */ - @SuppressLint("MethodNameTense") - void onEnable(@NonNull Consumer<Boolean> isAllowed); + void onEnableRequested(@NonNull Consumer<Boolean> isAllowed); /** * Method to check if Nfc is allowed to be disabled by OEMs. * @param isAllowed The {@link Consumer} to be completed. If disabling NFC is allowed, @@ -242,7 +265,7 @@ public final class NfcOemExtension { * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}. * false if NFC cannot be disabled at this time. */ - void onDisable(@NonNull Consumer<Boolean> isAllowed); + void onDisableRequested(@NonNull Consumer<Boolean> isAllowed); /** * Callback to indicate that Nfc starts to boot. @@ -255,7 +278,7 @@ public final class NfcOemExtension { void onEnableStarted(); /** - * Callback to indicate that Nfc starts to enable. + * Callback to indicate that Nfc starts to disable. */ void onDisableStarted(); @@ -287,8 +310,12 @@ public final class NfcOemExtension { /** * Notifies routing configuration is changed. + * @param isCommitRoutingSkipped The {@link Consumer} to be + * completed. If routing commit should be skipped, + * the {@link Consumer#accept(Object)} should be called with + * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}. */ - void onRoutingChanged(); + void onRoutingChanged(@NonNull Consumer<Boolean> isCommitRoutingSkipped); /** * API to activate start stop cpu boost on hce event. @@ -405,6 +432,19 @@ public final class NfcOemExtension { * @param item the log items that contains log information of NFC event. */ void onLogEventNotified(@NonNull OemLogItems item); + + /** + * Callback to to extract OEM defined packages from given NDEF message when + * a NFC tag is detected. These are used to handle NFC tags encoded with a + * proprietary format for storing app name (Android native app format). + * + * @param message NDEF message containing OEM package names + * @param packageConsumer The {@link Consumer} to be completed. + * The {@link Consumer#accept(Object)} should be called with + * the list of package names. + */ + void onExtractOemPackages(@NonNull NdefMessage message, + @NonNull Consumer<List<String>> packageConsumer); } @@ -605,12 +645,12 @@ public final class NfcOemExtension { /** * Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond. * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely - * use {@link #resumePolling() to resume the polling. - * @param timeoutInMs the pause polling duration in millisecond + * use {@link #resumePolling()} to resume the polling. + * @param timeoutInMs the pause polling duration in millisecond, ranging from 0 to 40000. */ @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) - public void pausePolling(int timeoutInMs) { + public void pausePolling(@DurationMillisLong int timeoutInMs) { NfcAdapter.callService(() -> NfcAdapter.sService.pausePolling(timeoutInMs)); } @@ -741,6 +781,18 @@ public final class NfcOemExtension { return result; } + /** + * API to force a routing table commit. + * @return a {@link StatusCode} to indicate if commit routing succeeded or not + */ + @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) + @CommitRoutingStatusCode + public int forceRoutingTableCommit() { + return NfcAdapter.callServiceReturn( + () -> NfcAdapter.sService.commitRouting(), COMMIT_ROUTING_STATUS_FAILED); + } + private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub { @Override @@ -799,13 +851,13 @@ public final class NfcOemExtension { public void onEnable(ResultReceiver isAllowed) throws RemoteException { mCallbackMap.forEach((cb, ex) -> handleVoidCallback( - new ReceiverWrapper<>(isAllowed), cb::onEnable, ex)); + new ReceiverWrapper<>(isAllowed), cb::onEnableRequested, ex)); } @Override public void onDisable(ResultReceiver isAllowed) throws RemoteException { mCallbackMap.forEach((cb, ex) -> handleVoidCallback( - new ReceiverWrapper<>(isAllowed), cb::onDisable, ex)); + new ReceiverWrapper<>(isAllowed), cb::onDisableRequested, ex)); } @Override public void onBootStarted() throws RemoteException { @@ -844,9 +896,10 @@ public final class NfcOemExtension { new ReceiverWrapper<>(isSkipped), cb::onTagDispatch, ex)); } @Override - public void onRoutingChanged() throws RemoteException { + public void onRoutingChanged(ResultReceiver isSkipped) throws RemoteException { mCallbackMap.forEach((cb, ex) -> - handleVoidCallback(null, (Object input) -> cb.onRoutingChanged(), ex)); + handleVoidCallback( + new ReceiverWrapper<>(isSkipped), cb::onRoutingChanged, ex)); } @Override public void onHceEventReceived(int action) throws RemoteException { @@ -925,6 +978,15 @@ public final class NfcOemExtension { handleVoidCallback(item, cb::onLogEventNotified, ex)); } + @Override + public void onExtractOemPackages(NdefMessage message, ResultReceiver packageConsumer) + throws RemoteException { + mCallbackMap.forEach((cb, ex) -> + handleVoid2ArgCallback(message, + new ReceiverWrapper<>(packageConsumer), + cb::onExtractOemPackages, ex)); + } + private <T> void handleVoidCallback( T input, Consumer<T> callbackMethod, Executor executor) { synchronized (mLock) { @@ -1035,8 +1097,14 @@ public final class NfcOemExtension { Bundle bundle = new Bundle(); bundle.putParcelable("intent", (Intent) result); mResultReceiver.send(0, bundle); + } else if (result instanceof List<?> list) { + if (list.stream().allMatch(String.class::isInstance)) { + Bundle bundle = new Bundle(); + bundle.putStringArray("packageNames", + list.stream().map(pkg -> (String) pkg).toArray(String[]::new)); + mResultReceiver.send(0, bundle); + } } - } @Override diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java index eb28c3b9c930..891752475824 100644 --- a/nfc/java/android/nfc/cardemulation/CardEmulation.java +++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java @@ -185,6 +185,65 @@ public final class CardEmulation { @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE) public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET = -1; + /** + * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} + * succeeded. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) + public static final int SET_SERVICE_ENABLED_STATUS_OK = 0; + + /** + * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} + * failed due to the unsupported feature. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) + public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1; + + /** + * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} + * failed due to the invalid service. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) + public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2; + + /** + * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} + * failed due to the service is already set to the requested status. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) + public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3; + + /** + * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} + * failed due to unknown error. + * @hide + */ + @SystemApi + @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) + public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4; + + /** + * Status code returned by {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)} + * @hide + */ + @IntDef(prefix = "SET_SERVICE_ENABLED_STATUS_", value = { + SET_SERVICE_ENABLED_STATUS_OK, + SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED, + SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE, + SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET, + SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SetServiceEnabledStatusCode {} + static boolean sIsInitialized = false; static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>(); static INfcCardEmulation sService; @@ -883,22 +942,24 @@ public final class CardEmulation { } /** - * Allows to set or unset preferred service (category other) to avoid AID Collision. + * Allows to set or unset preferred service (category other) to avoid AID Collision. The user + * should use corresponding context using {@link Context#createContextAsUser(UserHandle, int)} * * @param service The ComponentName of the service * @param status true to enable, false to disable - * @param userId the user handle of the user whose information is being requested. - * @return set service for the category and true if service is already set return false. + * @return true if preferred service is successfully set or unset, otherwise return false. * * @hide */ - public boolean setServiceEnabledForCategoryOther(ComponentName service, boolean status, - int userId) { - if (service == null) { - throw new NullPointerException("activity or service or category is null"); - } + @SystemApi + @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER) + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + @SetServiceEnabledStatusCode + public int setServiceEnabledForCategoryOther(@NonNull ComponentName service, + boolean status) { return callServiceReturn(() -> - sService.setServiceEnabledForCategoryOther(userId, service, status), false); + sService.setServiceEnabledForCategoryOther(mContext.getUser().getIdentifier(), + service, status), SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR); } /** @hide */ diff --git a/nfc/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig index 34f020012d3c..8a37aa28cf9d 100644 --- a/nfc/java/android/nfc/flags.aconfig +++ b/nfc/java/android/nfc/flags.aconfig @@ -173,3 +173,11 @@ flag { description: "Share wallet role routing priority with associated services" bug: "366243361" } + +flag { + name: "nfc_set_service_enabled_for_category_other" + is_exported: true + namespace: "nfc" + description: "Enable set service enabled for category other" + bug: "338157113" +} diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml index fadcf7ba8699..e68253e2200d 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-night-v35/themes.xml @@ -18,7 +18,7 @@ <style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight"> <item name="elevationOverlayEnabled">true</item> <item name="elevationOverlayColor">?attr/colorPrimary</item> - <item name="colorPrimary">@color/settingslib_materialColorOnSurfaceInverse</item> + <item name="colorPrimary">@color/settingslib_materialColorInverseOnSurface</item> <item name="colorAccent">@color/settingslib_materialColorPrimaryFixed</item> </style> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml index 7c9d1a47b7ef..f7c9aac68629 100644 --- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml +++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/values-v35/themes.xml @@ -18,7 +18,7 @@ <style name="Theme.CollapsingToolbar.Settings" parent="@style/Theme.MaterialComponents.DayNight"> <item name="elevationOverlayEnabled">true</item> <item name="elevationOverlayColor">?attr/colorPrimary</item> - <item name="colorPrimary">@color/settingslib_materialColorOnSurfaceInverse</item> + <item name="colorPrimary">@color/settingslib_materialColorInverseOnSurface</item> <item name="colorAccent">@color/settingslib_materialColorPrimary</item> </style> </resources>
\ No newline at end of file diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt index 5ceee6d09978..088bef230374 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/GetPreferenceGraphApiHandler.kt @@ -22,11 +22,13 @@ import com.android.settingslib.graph.proto.PreferenceGraphProto import com.android.settingslib.ipc.ApiHandler import com.android.settingslib.ipc.MessageCodec import com.android.settingslib.metadata.PreferenceScreenRegistry +import com.android.settingslib.preference.PreferenceScreenProvider import java.util.Locale /** API to get preference graph. */ -abstract class GetPreferenceGraphApiHandler : - ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> { +abstract class GetPreferenceGraphApiHandler( + private val preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>> +) : ApiHandler<GetPreferenceGraphRequest, PreferenceGraphProto> { override val requestCodec: MessageCodec<GetPreferenceGraphRequest> get() = GetPreferenceGraphRequestCodec @@ -40,14 +42,16 @@ abstract class GetPreferenceGraphApiHandler : callingUid: Int, request: GetPreferenceGraphRequest, ): PreferenceGraphProto { - val builderRequest = - if (request.screenKeys.isEmpty()) { - val keys = PreferenceScreenRegistry.preferenceScreens.keys - GetPreferenceGraphRequest(keys, request.visitedScreens, request.locale) - } else { - request + val builder = PreferenceGraphBuilder.of(application, request) + if (request.screenKeys.isEmpty()) { + for (key in PreferenceScreenRegistry.preferenceScreens.keys) { + builder.addPreferenceScreenFromRegistry(key) } - return PreferenceGraphBuilder.of(application, builderRequest).build() + for (provider in preferenceScreenProviders) { + builder.addPreferenceScreenProvider(provider) + } + } + return builder.build() } } diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt index 2256bb38dd2c..6760e72be4a6 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceGraphBuilder.kt @@ -133,7 +133,7 @@ private constructor(private val context: Context, private val request: GetPrefer null } - private suspend fun addPreferenceScreenFromRegistry(key: String): Boolean { + suspend fun addPreferenceScreenFromRegistry(key: String): Boolean { val metadata = PreferenceScreenRegistry[key] ?: return false return addPreferenceScreenMetadata(metadata) } @@ -146,7 +146,7 @@ private constructor(private val context: Context, private val request: GetPrefer } } - private suspend fun addPreferenceScreenProvider(activityClass: Class<*>) { + suspend fun addPreferenceScreenProvider(activityClass: Class<*>) { Log.d(TAG, "add $activityClass") createPreferenceScreen { activityClass.newInstance() } ?.let { diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt index 6e4db1d90484..7cfce0d85cd4 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/PreferenceSetterApi.kt @@ -22,6 +22,7 @@ import androidx.annotation.IntDef import com.android.settingslib.graph.proto.PreferenceValueProto import com.android.settingslib.ipc.ApiDescriptor import com.android.settingslib.ipc.ApiHandler +import com.android.settingslib.ipc.ApiPermissionChecker import com.android.settingslib.ipc.IntMessageCodec import com.android.settingslib.ipc.MessageCodec import com.android.settingslib.metadata.BooleanValue @@ -45,7 +46,11 @@ data class PreferenceSetterRequest( PreferenceSetterResult.OK, PreferenceSetterResult.UNSUPPORTED, PreferenceSetterResult.DISABLED, + PreferenceSetterResult.RESTRICTED, PreferenceSetterResult.UNAVAILABLE, + PreferenceSetterResult.REQUIRE_APP_PERMISSION, + PreferenceSetterResult.REQUIRE_USER_AGREEMENT, + PreferenceSetterResult.DISALLOW, PreferenceSetterResult.INVALID_REQUEST, PreferenceSetterResult.INTERNAL_ERROR, ) @@ -87,14 +92,17 @@ class PreferenceSetterApiDescriptor(override val id: Int) : } /** Preference setter API implementation. */ -class PreferenceSetterApiHandler(override val id: Int) : ApiHandler<PreferenceSetterRequest, Int> { +class PreferenceSetterApiHandler( + override val id: Int, + private val permissionChecker: ApiPermissionChecker<PreferenceSetterRequest>, +) : ApiHandler<PreferenceSetterRequest, Int> { override fun hasPermission( application: Application, myUid: Int, callingUid: Int, request: PreferenceSetterRequest, - ): Boolean = true + ) = permissionChecker.hasPermission(application, myUid, callingUid, request) override suspend fun invoke( application: Application, diff --git a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt index d9b9590f60e2..1bda277f2018 100644 --- a/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt +++ b/packages/SettingsLib/Graph/src/com/android/settingslib/graph/ProtoConverters.kt @@ -16,8 +16,10 @@ package com.android.settingslib.graph +import android.content.ComponentName import android.content.Context import android.content.Intent +import android.net.Uri import android.os.Bundle import com.android.settingslib.graph.proto.BundleProto import com.android.settingslib.graph.proto.BundleProto.BundleValue @@ -42,6 +44,20 @@ fun Intent.toProto(): IntentProto = intentProto { this@toProto.type?.let { mimeType = it } } +fun IntentProto.toIntent(): Intent? { + if (!hasComponent()) return null + val componentName = ComponentName.unflattenFromString(component) ?: return null + val intent = Intent() + intent.component = componentName + if (hasAction()) intent.action = action + if (hasData()) intent.data = Uri.parse(data) + if (hasPkg()) intent.`package` = pkg + if (hasFlags()) intent.flags = flags + if (hasExtras()) intent.putExtras(extras.toBundle()) + if (hasMimeType()) intent.setType(mimeType) + return intent +} + fun Bundle.toProto(): BundleProto = bundleProto { fun toProto(value: Any): BundleValue = bundleValueProto { when (value) { @@ -61,14 +77,18 @@ fun Bundle.toProto(): BundleProto = bundleProto { } } -fun BundleValue.stringify(): String = - when { - hasBooleanValue() -> "$valueCase" - hasBytesValue() -> "$bytesValue" - hasIntValue() -> "$intValue" - hasLongValue() -> "$longValue" - hasStringValue() -> stringValue - hasDoubleValue() -> "$doubleValue" - hasBundleValue() -> "$bundleValue" - else -> "Unknown" +fun BundleProto.toBundle(): Bundle = + Bundle().apply { + for ((key, value) in valuesMap) { + when { + value.hasBooleanValue() -> putBoolean(key, value.booleanValue) + value.hasBytesValue() -> putByteArray(key, value.bytesValue.toByteArray()) + value.hasIntValue() -> putInt(key, value.intValue) + value.hasLongValue() -> putLong(key, value.longValue) + value.hasStringValue() -> putString(key, value.stringValue) + value.hasDoubleValue() -> putDouble(key, value.doubleValue) + value.hasBundleValue() -> putBundle(key, value.bundleValue.toBundle()) + else -> throw IllegalArgumentException("Unknown type: ${value.javaClass} $value") + } + } } diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt index 802141dae7ec..4febd89a7da4 100644 --- a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt +++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/ApiHandler.kt @@ -56,6 +56,27 @@ interface ApiDescriptor<Request, Response> { val responseCodec: MessageCodec<Response> } +/** Permission checker for api. */ +fun interface ApiPermissionChecker<R> { + /** + * Returns if the request is permitted. + * + * @param application application context + * @param myUid uid of current process + * @param callingUid uid of peer process + * @param request API request + * @return `false` if permission is denied, otherwise `true` + */ + fun hasPermission(application: Application, myUid: Int, callingUid: Int, request: R): Boolean + + companion object { + private val ALWAYS_ALLOW = ApiPermissionChecker<Any> { _, _, _, _ -> true } + + @Suppress("UNCHECKED_CAST") + fun <T> alwaysAllow(): ApiPermissionChecker<T> = ALWAYS_ALLOW as ApiPermissionChecker<T> + } +} + /** * Handler of API. * @@ -64,18 +85,8 @@ interface ApiDescriptor<Request, Response> { * * The implementation must be threadsafe. */ -interface ApiHandler<Request, Response> : ApiDescriptor<Request, Response> { - /** - * Returns if the request is permitted. - * - * @return `false` if permission is denied, otherwise `true` - */ - fun hasPermission( - application: Application, - myUid: Int, - callingUid: Int, - request: Request, - ): Boolean +interface ApiHandler<Request, Response> : + ApiDescriptor<Request, Response>, ApiPermissionChecker<Request> { /** * Invokes the API. diff --git a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt index 7ffefed239a4..ef907e17d824 100644 --- a/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt +++ b/packages/SettingsLib/Ipc/src/com/android/settingslib/ipc/MessengerServiceClient.kt @@ -320,6 +320,11 @@ constructor( } } + override fun onNullBinding(name: ComponentName) { + Log.i(TAG, "onNullBinding $name") + close(ClientBindServiceException(null)) + } + internal open fun drainPendingRequests() { disposableHandle = null if (pendingRequests.isEmpty()) { diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt index 6e38df11156f..1823ba641775 100644 --- a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt +++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceGraphApi.kt @@ -19,9 +19,14 @@ package com.android.settingslib.service import android.app.Application import com.android.settingslib.graph.GetPreferenceGraphApiHandler import com.android.settingslib.graph.GetPreferenceGraphRequest +import com.android.settingslib.ipc.ApiPermissionChecker +import com.android.settingslib.preference.PreferenceScreenProvider /** Api to get preference graph. */ -internal class PreferenceGraphApi : GetPreferenceGraphApiHandler() { +internal class PreferenceGraphApi( + preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>>, + private val permissionChecker: ApiPermissionChecker<GetPreferenceGraphRequest>, +) : GetPreferenceGraphApiHandler(preferenceScreenProviders) { override val id: Int get() = API_GET_PREFERENCE_GRAPH @@ -31,5 +36,5 @@ internal class PreferenceGraphApi : GetPreferenceGraphApiHandler() { myUid: Int, callingUid: Int, request: GetPreferenceGraphRequest, - ) = true + ) = permissionChecker.hasPermission(application, myUid, callingUid, request) } diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt index 8ebb14522c3d..ed748bb58a9a 100644 --- a/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt +++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/PreferenceService.kt @@ -16,10 +16,14 @@ package com.android.settingslib.service +import com.android.settingslib.graph.GetPreferenceGraphRequest import com.android.settingslib.graph.PreferenceSetterApiHandler +import com.android.settingslib.graph.PreferenceSetterRequest import com.android.settingslib.ipc.ApiHandler +import com.android.settingslib.ipc.ApiPermissionChecker import com.android.settingslib.ipc.MessengerService import com.android.settingslib.ipc.PermissionChecker +import com.android.settingslib.preference.PreferenceScreenProvider /** * Preference service providing a bunch of APIs. @@ -28,14 +32,21 @@ import com.android.settingslib.ipc.PermissionChecker * [PREFERENCE_SERVICE_ACTION]. */ open class PreferenceService( - permissionChecker: PermissionChecker, name: String = "PreferenceService", + permissionChecker: PermissionChecker = PermissionChecker { _, _, _ -> true }, + preferenceScreenProviders: Set<Class<out PreferenceScreenProvider>> = setOf(), + graphPermissionChecker: ApiPermissionChecker<GetPreferenceGraphRequest>? = null, + setterPermissionChecker: ApiPermissionChecker<PreferenceSetterRequest>? = null, + vararg apiHandlers: ApiHandler<*, *>, ) : MessengerService( - listOf<ApiHandler<*, *>>( - PreferenceGraphApi(), - PreferenceSetterApiHandler(API_PREFERENCE_SETTER), - ), + mutableListOf<ApiHandler<*, *>>().apply { + graphPermissionChecker?.let { add(PreferenceGraphApi(preferenceScreenProviders, it)) } + setterPermissionChecker?.let { + add(PreferenceSetterApiHandler(API_PREFERENCE_SETTER, it)) + } + addAll(apiHandlers) + }, permissionChecker, name, ) diff --git a/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt b/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt index 1f38a6678eae..7655daa6cf21 100644 --- a/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt +++ b/packages/SettingsLib/Service/src/com/android/settingslib/service/ServiceApiConstants.kt @@ -18,5 +18,14 @@ package com.android.settingslib.service const val PREFERENCE_SERVICE_ACTION = "com.android.settingslib.PREFERENCE_SERVICE" +/** API id for retrieving preference graph. */ internal const val API_GET_PREFERENCE_GRAPH = 1 + +/** API id for preference value setter. */ internal const val API_PREFERENCE_SETTER = 2 + +/** + * The max API id reserved for internal preference service usages. Custom API id should start with + * **1000** to avoid conflict. + */ +internal const val API_MAX_RESERVED = 999 diff --git a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml index b46181e20eaa..8b574aa95176 100644 --- a/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml +++ b/packages/SettingsLib/SettingsTheme/res/color-v31/settingslib_surface_light.xml @@ -13,7 +13,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<!--Deprecated. After sdk 35, don't use it, using materialColorOnSurfaceInverse in light theme --> +<!--Deprecated. After sdk 35, don't use it, using materialColorInverseOnSurface in light theme --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@android:color/system_neutral1_500" android:lStar="98" /> </selector>
\ No newline at end of file diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml index 313748d8f091..46ec62e7a5ef 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-night-v31/colors.xml @@ -51,7 +51,7 @@ <color name="settingslib_text_color_preference_category_title">@android:color/system_accent1_100</color> - <!--Deprecated. After sdk 35, don't use it, using materialColorOnSurfaceInverse in dark theme --> + <!--Deprecated. After sdk 35, don't use it, using materialColorInverseOnSurface in dark theme --> <color name="settingslib_surface_dark">@android:color/system_neutral1_800</color> <!--Deprecated. After sdk 35, don't use it--> diff --git a/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml index 94ff02d898db..84a3ed68af01 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-night-v35/colors.xml @@ -53,11 +53,11 @@ <color name="settingslib_materialColorSurfaceContainerLow">@android:color/system_surface_container_low_dark</color> <color name="settingslib_materialColorOnPrimaryContainer">@android:color/system_on_primary_container_dark</color> <color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_dark</color> - <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_on_surface_light</color> + <color name="settingslib_materialColorInverseOnSurface">@android:color/system_on_surface_light</color> <color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_dark</color> <color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_dark</color> - <color name="settingslib_materialColorPrimaryInverse">@android:color/system_primary_light</color> - <color name="settingslib_materialColorSurfaceInverse">@android:color/system_surface_light</color> + <color name="settingslib_materialColorInversePrimary">@android:color/system_primary_light</color> + <color name="settingslib_materialColorInverseSurface">@android:color/system_surface_light</color> <color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_dark</color> <color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_dark</color> <color name="settingslib_materialColorPrimaryContainer">@android:color/system_primary_container_dark</color> diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml index b99ee5123491..fef92b792bec 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v31/colors.xml @@ -67,9 +67,9 @@ <color name="settingslib_accent_primary_variant">@android:color/system_accent1_600</color> <!--Deprecated. After sdk 35 don't use it.--> <color name="settingslib_accent_secondary_device_default">@android:color/system_accent2_100</color> - <!--Deprecated. After sdk 35 don't use it.using materialColorOnSurfaceInverse in dark theme--> + <!--Deprecated. After sdk 35 don't use it.using materialColorInverseOnSurface in dark theme--> <color name="settingslib_background_device_default_dark">@android:color/system_neutral1_900</color> - <!--Deprecated. After sdk 35 don't use it. using materialColorOnSurfaceInverse in light theme--> + <!--Deprecated. After sdk 35 don't use it. using materialColorInverseOnSurface in light theme--> <color name="settingslib_background_device_default_light">@android:color/system_neutral1_50</color> <!--Deprecated. After sdk 35 don't use it. using materialColorOnSurface--> <color name="settingslib_text_color_primary_device_default">@android:color/system_neutral1_900</color> diff --git a/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml b/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml index 8b9501608000..90c19e1aa676 100644 --- a/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml +++ b/packages/SettingsLib/SettingsTheme/res/values-v35/colors.xml @@ -66,16 +66,16 @@ <color name="settingslib_materialColorSecondaryFixedDim">@android:color/system_secondary_fixed_dim</color> <color name="settingslib_materialColorOnErrorContainer">@android:color/system_on_error_container_light</color> <color name="settingslib_materialColorOnSecondaryFixed">@android:color/system_on_secondary_fixed</color> - <color name="settingslib_materialColorOnSurfaceInverse">@android:color/system_on_surface_dark</color> + <color name="settingslib_materialColorInverseOnSurface">@android:color/system_on_surface_dark</color> <color name="settingslib_materialColorTertiaryFixedDim">@android:color/system_tertiary_fixed_dim</color> <color name="settingslib_materialColorOnTertiaryFixed">@android:color/system_on_tertiary_fixed</color> <color name="settingslib_materialColorPrimaryFixedDim">@android:color/system_primary_fixed_dim</color> <color name="settingslib_materialColorSecondaryContainer">@android:color/system_secondary_container_light</color> <color name="settingslib_materialColorErrorContainer">@android:color/system_error_container_light</color> <color name="settingslib_materialColorOnPrimaryFixed">@android:color/system_on_primary_fixed</color> - <color name="settingslib_materialColorPrimaryInverse">@android:color/system_primary_dark</color> + <color name="settingslib_materialColorInversePrimary">@android:color/system_primary_dark</color> <color name="settingslib_materialColorSecondaryFixed">@android:color/system_secondary_fixed</color> - <color name="settingslib_materialColorSurfaceInverse">@android:color/system_surface_dark</color> + <color name="settingslib_materialColorInverseSurface">@android:color/system_surface_dark</color> <color name="settingslib_materialColorSurfaceVariant">@android:color/system_surface_variant_light</color> <color name="settingslib_materialColorTertiaryContainer">@android:color/system_tertiary_container_light</color> <color name="settingslib_materialColorTertiaryFixed">@android:color/system_tertiary_fixed</color> diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java index 83ee9751329f..80e5e5981912 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InputMediaDevice.java @@ -15,6 +15,7 @@ */ package com.android.settingslib.media; +import static android.media.AudioDeviceInfo.TYPE_BLE_HEADSET; import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_SCO; import static android.media.AudioDeviceInfo.TYPE_BUILTIN_MIC; import static android.media.AudioDeviceInfo.TYPE_USB_ACCESSORY; @@ -103,7 +104,8 @@ public class InputMediaDevice extends MediaDevice { TYPE_USB_DEVICE, TYPE_USB_HEADSET, TYPE_USB_ACCESSORY, - TYPE_BLUETOOTH_SCO -> + TYPE_BLUETOOTH_SCO, + TYPE_BLE_HEADSET -> true; default -> false; }; @@ -124,7 +126,7 @@ public class InputMediaDevice extends MediaDevice { mProductName != null ? mProductName : mContext.getString(R.string.media_transfer_usb_device_mic_name); - case TYPE_BLUETOOTH_SCO -> + case TYPE_BLUETOOTH_SCO, TYPE_BLE_HEADSET -> mProductName != null ? mProductName : mContext.getString(R.string.media_transfer_bt_device_mic_name); diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java index 5eeb49a0b398..6842d0a949af 100644 --- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java +++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/TestModeBuilder.java @@ -204,6 +204,13 @@ public class TestModeBuilder { return this; } + public TestModeBuilder implicitForPackage(String pkg) { + setPackage(pkg); + setId(ZenModeConfig.implicitRuleId(pkg)); + setName("Do Not Disturb (" + pkg + ")"); + return this; + } + public TestModeBuilder setActive(boolean active) { if (active) { mConfigZenRule.enabled = true; diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java index 34d3bd9846d0..d5cfe55813ee 100644 --- a/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java +++ b/packages/SettingsLib/src/com/android/settingslib/notification/modes/ZenMode.java @@ -208,6 +208,11 @@ public class ZenMode implements Parcelable { } @NonNull + public Kind getKind() { + return mKind; + } + + @NonNull public Status getStatus() { return mStatus; } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java index 7775b912e51d..8624c4df833b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InputMediaDeviceTest.java @@ -38,6 +38,7 @@ public class InputMediaDeviceTest { private final int WIRED_HEADSET_ID = 2; private final int USB_HEADSET_ID = 3; private final int BT_HEADSET_ID = 4; + private final int BLE_HEADSET_ID = 5; private final int MAX_VOLUME = 1; private final int CURRENT_VOLUME = 0; private final boolean IS_VOLUME_FIXED = true; @@ -45,6 +46,7 @@ public class InputMediaDeviceTest { private static final String PRODUCT_NAME_WIRED_HEADSET = "My Wired Headset"; private static final String PRODUCT_NAME_USB_HEADSET = "My USB Headset"; private static final String PRODUCT_NAME_BT_HEADSET = "My Bluetooth Headset"; + private static final String PRODUCT_NAME_BLE_HEADSET = "My BLE Headset"; @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -163,4 +165,35 @@ public class InputMediaDeviceTest { assertThat(btMediaDevice.getName()) .isEqualTo(mContext.getString(R.string.media_transfer_bt_device_mic_name)); } + + @Test + public void getName_returnCorrectName_bleHeadset() { + InputMediaDevice bleMediaDevice = + InputMediaDevice.create( + mContext, + String.valueOf(BLE_HEADSET_ID), + AudioDeviceInfo.TYPE_BLE_HEADSET, + MAX_VOLUME, + CURRENT_VOLUME, + IS_VOLUME_FIXED, + PRODUCT_NAME_BLE_HEADSET); + assertThat(bleMediaDevice).isNotNull(); + assertThat(bleMediaDevice.getName()).isEqualTo(PRODUCT_NAME_BLE_HEADSET); + } + + @Test + public void getName_returnCorrectName_bleHeadset_nullProductName() { + InputMediaDevice bleMediaDevice = + InputMediaDevice.create( + mContext, + String.valueOf(BLE_HEADSET_ID), + AudioDeviceInfo.TYPE_BLE_HEADSET, + MAX_VOLUME, + CURRENT_VOLUME, + IS_VOLUME_FIXED, + null); + assertThat(bleMediaDevice).isNotNull(); + assertThat(bleMediaDevice.getName()) + .isEqualTo(mContext.getString(R.string.media_transfer_bt_device_mic_name)); + } } diff --git a/packages/SettingsProvider/res/xml/bookmarks.xml b/packages/SettingsProvider/res/xml/bookmarks.xml index 22d02262c388..645b275e2af5 100644 --- a/packages/SettingsProvider/res/xml/bookmarks.xml +++ b/packages/SettingsProvider/res/xml/bookmarks.xml @@ -32,6 +32,9 @@ 'y': YouTube --> <bookmarks> + <!-- TODO(b/358569822): Remove this from Settings DB + This is legacy implementation to store bookmarks in Settings DB, which is deprecated and + no longer used --> <bookmark role="android.app.role.BROWSER" shortcut="b" /> diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 7b6321d1cc7d..526320debb1a 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -369,6 +369,9 @@ <!-- Permission needed for CTS test - UnsupportedErrorDialogTests --> <uses-permission android:name="android.permission.RESET_APP_ERRORS" /> + <!-- Permission needed tests --> + <uses-permission android:name="android.permission.OBSERVE_PICTURE_PROFILES" /> + <!-- Permission needed for CTS test - CtsSystemUiTestCases:PipNotificationTests --> <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" /> @@ -953,6 +956,13 @@ <uses-permission android:name="android.permission.QUERY_ADVANCED_PROTECTION_MODE" android:featureFlag="android.security.aapm_api"/> + <!-- Permission required for CTS test - ForensicManagerTest --> + <uses-permission android:name="android.permission.READ_FORENSIC_STATE" + android:featureFlag="android.security.afl_api"/> + <uses-permission android:name="android.permission.MANAGE_FORENSIC_STATE" + android:featureFlag="android.security.afl_api"/> + + <!-- Permission required for CTS test - CtsAppTestCases --> <uses-permission android:name="android.permission.KILL_UID" /> diff --git a/packages/Shell/aconfig/Android.bp b/packages/Shell/aconfig/Android.bp new file mode 100644 index 000000000000..1d797b29c1a4 --- /dev/null +++ b/packages/Shell/aconfig/Android.bp @@ -0,0 +1,13 @@ +aconfig_declarations { + name: "wear_aconfig_declarations", + package: "com.android.shell.flags", + container: "system", + srcs: [ + "wear.aconfig", + ], +} + +java_aconfig_library { + name: "wear_aconfig_declarations_flags_java_lib", + aconfig_declarations: "wear_aconfig_declarations", +} diff --git a/packages/Shell/aconfig/wear.aconfig b/packages/Shell/aconfig/wear.aconfig new file mode 100644 index 000000000000..e07bd963a4aa --- /dev/null +++ b/packages/Shell/aconfig/wear.aconfig @@ -0,0 +1,9 @@ +package: "com.android.shell.flags" +container: "system" + +flag { + name: "handle_bugreports_for_wear" + namespace: "wear_services" + description: "This flag enables Shell to propagate bugreport results to WearServices." + bug: "378060870" +}
\ No newline at end of file diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index dafe38dc5c00..d1a22e8612d3 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -208,7 +208,9 @@ filegroup { "tests/src/**/systemui/qs/tiles/DreamTileTest.java", "tests/src/**/systemui/qs/FgsManagerControllerTest.java", "tests/src/**/systemui/qs/QSPanelTest.kt", + "tests/src/**/systemui/reardisplay/RearDisplayCoreStartableTest.kt", "tests/src/**/systemui/reardisplay/RearDisplayDialogControllerTest.java", + "tests/src/**/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt", "tests/src/**/systemui/statusbar/KeyboardShortcutListSearchTest.java", "tests/src/**/systemui/statusbar/KeyboardShortcutsTest.java", "tests/src/**/systemui/statusbar/KeyguardIndicationControllerWithCoroutinesTest.kt", diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index a4b8821383e0..123f82393679 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -1748,6 +1748,13 @@ flag { } flag { + name: "notification_shade_blur" + namespace: "systemui" + description: "Enables the new blur effect on the Notification Shade." + bug: "370555223" +} + +flag { name: "ensure_enr_views_visibility" namespace: "systemui" description: "Ensures public and private visibilities" @@ -1790,4 +1797,4 @@ flag { metadata { purpose: PURPOSE_BUGFIX } -}
\ No newline at end of file +} 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 18f40c98fe04..eee0cafd34fe 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt @@ -24,18 +24,22 @@ import android.app.WindowConfiguration import android.content.ComponentName import android.graphics.Color import android.graphics.Matrix +import android.graphics.PointF import android.graphics.Rect import android.graphics.RectF import android.os.Binder import android.os.Build import android.os.Handler +import android.os.IBinder import android.os.Looper import android.os.RemoteException +import android.util.ArrayMap import android.util.Log import android.view.IRemoteAnimationFinishedCallback import android.view.IRemoteAnimationRunner import android.view.RemoteAnimationAdapter import android.view.RemoteAnimationTarget +import android.view.SurfaceControl import android.view.SyncRtSurfaceTransactionApplier import android.view.View import android.view.ViewGroup @@ -45,8 +49,12 @@ import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_BACK import android.view.WindowManager.TRANSIT_TO_FRONT import android.view.animation.PathInterpolator +import android.window.IRemoteTransition +import android.window.IRemoteTransitionFinishedCallback import android.window.RemoteTransition import android.window.TransitionFilter +import android.window.TransitionInfo +import android.window.WindowAnimationState import androidx.annotation.AnyThread import androidx.annotation.BinderThread import androidx.annotation.UiThread @@ -55,11 +63,14 @@ import com.android.internal.annotations.VisibleForTesting import com.android.internal.policy.ScreenDecorationsUtils import com.android.systemui.Flags.activityTransitionUseLargestWindow import com.android.systemui.Flags.translucentOccludingActivityFix +import com.android.systemui.animation.TransitionAnimator.Companion.assertLongLivedReturnAnimations +import com.android.systemui.animation.TransitionAnimator.Companion.assertReturnAnimations +import com.android.systemui.animation.TransitionAnimator.Companion.longLivedReturnAnimationsEnabled +import com.android.systemui.animation.TransitionAnimator.Companion.returnAnimationsEnabled import com.android.systemui.animation.TransitionAnimator.Companion.toTransitionState -import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary -import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived import com.android.wm.shell.shared.IShellTransitions import com.android.wm.shell.shared.ShellTransitions +import com.android.wm.shell.shared.TransitionUtil import java.util.concurrent.Executor import kotlin.math.roundToInt @@ -194,7 +205,13 @@ constructor( private const val LONG_TRANSITION_TIMEOUT = 5_000L private fun defaultTransitionAnimator(mainExecutor: Executor): TransitionAnimator { - return TransitionAnimator(mainExecutor, TIMINGS, INTERPOLATORS) + return TransitionAnimator( + mainExecutor, + TIMINGS, + INTERPOLATORS, + SPRING_TIMINGS, + SPRING_INTERPOLATORS, + ) } private fun defaultDialogToAppAnimator(mainExecutor: Executor): TransitionAnimator { @@ -275,7 +292,7 @@ constructor( "ActivityTransitionAnimator.callback must be set before using this animator" ) val runner = createRunner(controller) - val runnerDelegate = runner.delegate!! + val runnerDelegate = runner.delegate val hideKeyguardWithAnimation = callback.isOnKeyguard() && !showOverLockscreen // Pass the RemoteAnimationAdapter to the intent starter only if we are not hiding the @@ -330,7 +347,11 @@ constructor( // If we expect an animation, post a timeout to cancel it in case the remote animation is // never started. if (willAnimate) { - runnerDelegate.postTimeouts() + if (longLivedReturnAnimationsEnabled()) { + runner.postTimeouts() + } else { + runnerDelegate!!.postTimeouts() + } // Hide the keyguard using the launch animation instead of the default unlock animation. if (hideKeyguardWithAnimation) { @@ -390,7 +411,7 @@ constructor( launchController: Controller, transitionRegister: TransitionRegister?, ) { - if (!returnAnimationFrameworkLibrary()) return + if (!returnAnimationsEnabled()) return var cleanUpRunnable: Runnable? = null val returnRunner = @@ -413,7 +434,8 @@ constructor( private fun cleanUp() { cleanUpRunnable?.run() } - } + }, + initializeLazily = longLivedReturnAnimationsEnabled(), ) // mTypeSet and mModes match back signals only, and not home. This is on purpose, because @@ -435,7 +457,11 @@ constructor( "${launchController.transitionCookie}_returnTransition", ) - transitionRegister?.register(filter, transition) + transitionRegister?.register( + filter, + transition, + includeTakeover = longLivedReturnAnimationsEnabled(), + ) cleanUpRunnable = Runnable { transitionRegister?.unregister(transition) } } @@ -451,7 +477,10 @@ constructor( /** Create a new animation [Runner] controlled by [controller]. */ @VisibleForTesting - fun createRunner(controller: Controller): Runner { + @JvmOverloads + fun createRunner(controller: Controller, initializeLazily: Boolean = false): Runner { + if (initializeLazily) assertLongLivedReturnAnimations() + // Make sure we use the modified timings when animating a dialog into an app. val transitionAnimator = if (controller.isDialogLaunch) { @@ -460,7 +489,13 @@ constructor( transitionAnimator } - return Runner(controller, callback!!, transitionAnimator, lifecycleListener) + return Runner( + controller, + callback!!, + transitionAnimator, + lifecycleListener, + initializeLazily, + ) } interface PendingIntentStarter { @@ -628,10 +663,7 @@ constructor( * this registration. */ fun register(controller: Controller) { - check(returnAnimationFrameworkLongLived()) { - "Long-lived registrations cannot be used when the returnAnimationFrameworkLongLived " + - "flag is disabled" - } + assertLongLivedReturnAnimations() if (transitionRegister == null) { throw IllegalStateException( @@ -667,10 +699,10 @@ constructor( } val launchRemoteTransition = RemoteTransition( - RemoteAnimationRunnerCompat.wrap(createRunner(controller)), + OriginTransition(createRunner(controller, initializeLazily = true)), "${cookie}_launchTransition", ) - transitionRegister.register(launchFilter, launchRemoteTransition) + transitionRegister.register(launchFilter, launchRemoteTransition, includeTakeover = true) val returnController = object : Controller by controller { @@ -689,10 +721,10 @@ constructor( } val returnRemoteTransition = RemoteTransition( - RemoteAnimationRunnerCompat.wrap(createRunner(returnController)), + OriginTransition(createRunner(returnController, initializeLazily = true)), "${cookie}_returnTransition", ) - transitionRegister.register(returnFilter, returnRemoteTransition) + transitionRegister.register(returnFilter, returnRemoteTransition, includeTakeover = true) longLivedTransitions[cookie] = Pair(launchRemoteTransition, returnRemoteTransition) } @@ -738,14 +770,154 @@ constructor( } } + /** [Runner] wrapper that supports animation takeovers. */ + private inner class OriginTransition(private val runner: Runner) : IRemoteTransition { + private val delegate = RemoteAnimationRunnerCompat.wrap(runner) + + init { + assertLongLivedReturnAnimations() + } + + override fun startAnimation( + token: IBinder?, + info: TransitionInfo?, + t: SurfaceControl.Transaction?, + finishCallback: IRemoteTransitionFinishedCallback?, + ) { + delegate.startAnimation(token, info, t, finishCallback) + } + + override fun mergeAnimation( + transition: IBinder?, + info: TransitionInfo?, + t: SurfaceControl.Transaction?, + mergeTarget: IBinder?, + finishCallback: IRemoteTransitionFinishedCallback?, + ) { + delegate.mergeAnimation(transition, info, t, mergeTarget, finishCallback) + } + + override fun onTransitionConsumed(transition: IBinder?, aborted: Boolean) { + delegate.onTransitionConsumed(transition, aborted) + } + + override fun takeOverAnimation( + token: IBinder?, + info: TransitionInfo?, + t: SurfaceControl.Transaction?, + finishCallback: IRemoteTransitionFinishedCallback?, + states: Array<WindowAnimationState>, + ) { + if (info == null || t == null) { + Log.e( + TAG, + "Skipping the animation takeover because the required data is missing: " + + "info=$info, transaction=$t", + ) + return + } + + // The following code converts the contents of the given TransitionInfo into + // RemoteAnimationTargets. This is necessary because we must currently support both the + // new (Shell, remote transitions) and old (remote animations) framework to maintain + // functionality for all users of the library. + val apps = ArrayList<RemoteAnimationTarget>() + val filteredStates = ArrayList<WindowAnimationState>() + val leashMap = ArrayMap<SurfaceControl, SurfaceControl>() + val leafTaskFilter = TransitionUtil.LeafTaskFilter() + + // About layering: we divide up the "layer space" into 2 regions (each the size of the + // change count). This lets us categorize things into above and below while + // maintaining their relative ordering. + val belowLayers = info.changes.size + val aboveLayers = info.changes.size * 2 + for (i in info.changes.indices) { + val change = info.changes[i] + if (change == null || change.taskInfo == null) { + continue + } + + val taskInfo = change.taskInfo + + if (TransitionUtil.isWallpaper(change)) { + val target = + TransitionUtil.newTarget( + change, + belowLayers - i, // wallpapers go into the "below" layer space + info, + t, + leashMap, + ) + + // Make all the wallpapers opaque. + t.setAlpha(target.leash, 1f) + } else if (leafTaskFilter.test(change)) { + // Start by putting everything into the "below" layer space. + val target = + TransitionUtil.newTarget(change, belowLayers - i, info, t, leashMap) + apps.add(target) + filteredStates.add(states[i]) + + // Make all the apps opaque. + t.setAlpha(target.leash, 1f) + + if ( + TransitionUtil.isClosingType(change.mode) && + taskInfo?.topActivityType != WindowConfiguration.ACTIVITY_TYPE_HOME + ) { + // Raise closing task to "above" layer so it isn't covered. + t.setLayer(target.leash, aboveLayers - i) + } + } else if (TransitionInfo.isIndependent(change, info)) { + // Root tasks + if (TransitionUtil.isClosingType(change.mode)) { + // Raise closing task to "above" layer so it isn't covered. + t.setLayer(change.leash, aboveLayers - i) + } else if (TransitionUtil.isOpeningType(change.mode)) { + // Put into the "below" layer space. + t.setLayer(change.leash, belowLayers - i) + } + } else if (TransitionUtil.isDividerBar(change)) { + val target = + TransitionUtil.newTarget(change, belowLayers - i, info, t, leashMap) + apps.add(target) + filteredStates.add(states[i]) + } + } + + val wrappedCallback: IRemoteAnimationFinishedCallback = + object : IRemoteAnimationFinishedCallback.Stub() { + override fun onAnimationFinished() { + leashMap.clear() + val finishTransaction = SurfaceControl.Transaction() + finishCallback?.onTransitionFinished(null, finishTransaction) + finishTransaction.close() + } + } + + runner.takeOverAnimation( + apps.toTypedArray(), + filteredStates.toTypedArray(), + t, + wrappedCallback, + ) + } + + override fun asBinder(): IBinder { + return delegate.asBinder() + } + } + @VisibleForTesting inner class Runner( - controller: Controller, - callback: Callback, + private val controller: Controller, + private val callback: Callback, /** The animator to use to animate the window transition. */ - transitionAnimator: TransitionAnimator, + private val transitionAnimator: TransitionAnimator, /** Listener for animation lifecycle events. */ - listener: Listener? = null, + private val listener: Listener? = null, + /** Whether the internal [delegate] should be initialized lazily. */ + private val initializeLazily: Boolean = false, ) : IRemoteAnimationRunner.Stub() { // This is being passed across IPC boundaries and cycles (through PendingIntentRecords, // etc.) are possible. So we need to make sure we drop any references that might @@ -753,15 +925,14 @@ constructor( @VisibleForTesting var delegate: AnimationDelegate? init { - delegate = - AnimationDelegate( - mainExecutor, - controller, - callback, - DelegatingAnimationCompletionListener(listener, this::dispose), - transitionAnimator, - disableWmTimeout, - ) + delegate = null + if (!initializeLazily) { + // Ephemeral launches bundle the runner with the launch request (instead of being + // registered ahead of time for later use). This means that there could be a timeout + // between creation and invocation, so the delegate needs to exist from the + // beginning in order to handle such timeout. + createDelegate() + } } @BinderThread @@ -772,6 +943,36 @@ constructor( nonApps: Array<out RemoteAnimationTarget>?, finishedCallback: IRemoteAnimationFinishedCallback?, ) { + initAndRun(finishedCallback) { delegate -> + delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback) + } + } + + @VisibleForTesting + @BinderThread + fun takeOverAnimation( + apps: Array<RemoteAnimationTarget>?, + windowAnimationStates: Array<WindowAnimationState>, + startTransaction: SurfaceControl.Transaction, + finishedCallback: IRemoteAnimationFinishedCallback?, + ) { + assertLongLivedReturnAnimations() + initAndRun(finishedCallback) { delegate -> + delegate.takeOverAnimation( + apps, + windowAnimationStates, + startTransaction, + finishedCallback, + ) + } + } + + @BinderThread + private fun initAndRun( + finishedCallback: IRemoteAnimationFinishedCallback?, + performAnimation: (AnimationDelegate) -> Unit, + ) { + maybeSetUp() val delegate = delegate mainExecutor.execute { if (delegate == null) { @@ -780,7 +981,7 @@ constructor( // signal back that we're done with it. finishedCallback?.onAnimationFinished() } else { - delegate.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback) + performAnimation(delegate) } } } @@ -794,6 +995,32 @@ constructor( } } + @VisibleForTesting + @UiThread + fun postTimeouts() { + maybeSetUp() + delegate?.postTimeouts() + } + + @AnyThread + private fun maybeSetUp() { + if (!initializeLazily || delegate != null) return + createDelegate() + } + + @AnyThread + private fun createDelegate() { + delegate = + AnimationDelegate( + mainExecutor, + controller, + callback, + DelegatingAnimationCompletionListener(listener, this::dispose), + transitionAnimator, + disableWmTimeout, + ) + } + @AnyThread fun dispose() { // Drop references to animation controller once we're done with the animation @@ -867,7 +1094,7 @@ constructor( init { // We do this check here to cover all entry points, including Launcher which doesn't // call startIntentWithAnimation() - if (!controller.isLaunching) TransitionAnimator.checkReturnAnimationFrameworkFlag() + if (!controller.isLaunching) assertReturnAnimations() } @UiThread @@ -893,19 +1120,73 @@ constructor( nonApps: Array<out RemoteAnimationTarget>?, callback: IRemoteAnimationFinishedCallback?, ) { + val window = setUpAnimation(apps, callback) ?: return + + if (controller.windowAnimatorState == null || !longLivedReturnAnimationsEnabled()) { + val navigationBar = + nonApps?.firstOrNull { + it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR + } + + startAnimation(window, navigationBar, iCallback = callback) + } else { + // If a [controller.windowAnimatorState] exists, treat this like a takeover. + takeOverAnimationInternal( + window, + startWindowStates = null, + startTransaction = null, + callback, + ) + } + } + + @UiThread + internal fun takeOverAnimation( + apps: Array<out RemoteAnimationTarget>?, + startWindowStates: Array<WindowAnimationState>, + startTransaction: SurfaceControl.Transaction, + callback: IRemoteAnimationFinishedCallback?, + ) { + val window = setUpAnimation(apps, callback) ?: return + takeOverAnimationInternal(window, startWindowStates, startTransaction, callback) + } + + private fun takeOverAnimationInternal( + window: RemoteAnimationTarget, + startWindowStates: Array<WindowAnimationState>?, + startTransaction: SurfaceControl.Transaction?, + callback: IRemoteAnimationFinishedCallback?, + ) { + val useSpring = + !controller.isLaunching && startWindowStates != null && startTransaction != null + startAnimation( + window, + navigationBar = null, + useSpring, + startWindowStates, + startTransaction, + callback, + ) + } + + @UiThread + private fun setUpAnimation( + apps: Array<out RemoteAnimationTarget>?, + callback: IRemoteAnimationFinishedCallback?, + ): RemoteAnimationTarget? { removeTimeouts() // The animation was started too late and we already notified the controller that it // timed out. if (timedOut) { callback?.invoke() - return + return null } // This should not happen, but let's make sure we don't start the animation if it was // cancelled before and we already notified the controller. if (cancelled) { - return + return null } val window = findTargetWindowIfPossible(apps) @@ -921,15 +1202,10 @@ constructor( } controller.onTransitionAnimationCancelled() listener?.onTransitionAnimationCancelled() - return + return null } - val navigationBar = - nonApps?.firstOrNull { - it.windowType == WindowManager.LayoutParams.TYPE_NAVIGATION_BAR - } - - startAnimation(window, navigationBar, callback) + return window } private fun findTargetWindowIfPossible( @@ -950,7 +1226,7 @@ constructor( for (it in apps) { if (it.mode == targetMode) { if (activityTransitionUseLargestWindow()) { - if (returnAnimationFrameworkLibrary()) { + if (returnAnimationsEnabled()) { // If the controller contains a cookie, _only_ match if either the // candidate contains the matching cookie, or a component is also // defined and is a match. @@ -995,8 +1271,11 @@ constructor( private fun startAnimation( window: RemoteAnimationTarget, - navigationBar: RemoteAnimationTarget?, - iCallback: IRemoteAnimationFinishedCallback?, + navigationBar: RemoteAnimationTarget? = null, + useSpring: Boolean = false, + startingWindowStates: Array<WindowAnimationState>? = null, + startTransaction: SurfaceControl.Transaction? = null, + iCallback: IRemoteAnimationFinishedCallback? = null, ) { if (TransitionAnimator.DEBUG) { Log.d(TAG, "Remote animation started") @@ -1046,18 +1325,66 @@ constructor( val controller = object : Controller by delegate { override fun createAnimatorState(): TransitionAnimator.State { - if (isLaunching) return delegate.createAnimatorState() - return delegate.windowAnimatorState?.toTransitionState() - ?: getWindowRadius(isExpandingFullyAbove).let { - TransitionAnimator.State( - top = windowBounds.top, - bottom = windowBounds.bottom, - left = windowBounds.left, - right = windowBounds.right, - topCornerRadius = it, - bottomCornerRadius = it, - ) + if (isLaunching) { + return delegate.createAnimatorState() + } else if (!longLivedReturnAnimationsEnabled()) { + return delegate.windowAnimatorState?.toTransitionState() + ?: getWindowRadius(isExpandingFullyAbove).let { + TransitionAnimator.State( + top = windowBounds.top, + bottom = windowBounds.bottom, + left = windowBounds.left, + right = windowBounds.right, + topCornerRadius = it, + bottomCornerRadius = it, + ) + } + } + + // The states are sorted matching the changes inside the transition info. + // Using this info, the RemoteAnimationTargets are created, with their + // prefixOrderIndex fields in reverse order to that of changes. To extract + // the right state, we need to invert again. + val windowState = + if (startingWindowStates != null) { + startingWindowStates[ + startingWindowStates.size - window.prefixOrderIndex] + } else { + controller.windowAnimatorState } + + // TODO(b/323863002): use the timestamp and velocity to update the initial + // position. + val bounds = windowState?.bounds + val left: Int = bounds?.left?.toInt() ?: windowBounds.left + val top: Int = bounds?.top?.toInt() ?: windowBounds.top + val right: Int = bounds?.right?.toInt() ?: windowBounds.right + val bottom: Int = bounds?.bottom?.toInt() ?: windowBounds.bottom + + val width = windowBounds.right - windowBounds.left + val height = windowBounds.bottom - windowBounds.top + // Scale the window. We use the max of (widthRatio, heightRatio) so that + // there is no blank space on any side. + val widthRatio = (right - left).toFloat() / width + val heightRatio = (bottom - top).toFloat() / height + val startScale = maxOf(widthRatio, heightRatio) + + val maybeRadius = windowState?.topLeftRadius + val windowRadius = + if (maybeRadius != null) { + maybeRadius * startScale + } else { + getWindowRadius(isExpandingFullyAbove) + } + + return TransitionAnimator.State( + top = top, + bottom = bottom, + left = left, + right = right, + topCornerRadius = windowRadius, + bottomCornerRadius = windowRadius, + ) } override fun onTransitionAnimationStart(isExpandingFullyAbove: Boolean) { @@ -1071,6 +1398,19 @@ constructor( "[controller=$delegate]", ) } + + if (startTransaction != null) { + // Calling applyStateToWindow() here avoids skipping a frame when taking + // over an animation. + applyStateToWindow( + window, + createAnimatorState(), + linearProgress = 0f, + useSpring, + startTransaction, + ) + } + delegate.onTransitionAnimationStart(isExpandingFullyAbove) } @@ -1094,14 +1434,29 @@ constructor( progress: Float, linearProgress: Float, ) { - applyStateToWindow(window, state, linearProgress) + applyStateToWindow(window, state, linearProgress, useSpring) navigationBar?.let { applyStateToNavigationBar(it, state, linearProgress) } listener?.onTransitionAnimationProgress(linearProgress) delegate.onTransitionAnimationProgress(state, progress, linearProgress) } } - + val windowState = + if (startingWindowStates != null) { + startingWindowStates[startingWindowStates.size - window.prefixOrderIndex] + } else { + controller.windowAnimatorState + } + val velocityPxPerS = + if (longLivedReturnAnimationsEnabled() && windowState?.velocityPxPerMs != null) { + val xVelocityPxPerS = windowState.velocityPxPerMs.x * 1000 + val yVelocityPxPerS = windowState.velocityPxPerMs.y * 1000 + PointF(xVelocityPxPerS, yVelocityPxPerS) + } else if (useSpring) { + PointF(0f, 0f) + } else { + null + } animation = transitionAnimator.startAnimation( controller, @@ -1109,6 +1464,7 @@ constructor( windowBackgroundColor, fadeWindowBackgroundLayer = !controller.isBelowAnimatingWindow, drawHole = !controller.isBelowAnimatingWindow, + startVelocity = velocityPxPerS, ) } @@ -1128,6 +1484,8 @@ constructor( window: RemoteAnimationTarget, state: TransitionAnimator.State, linearProgress: Float, + useSpring: Boolean, + transaction: SurfaceControl.Transaction? = null, ) { if (transactionApplierView.viewRootImpl == null || !window.leash.isValid) { // Don't apply any transaction if the view root we synchronize with was detached or @@ -1171,25 +1529,47 @@ constructor( windowCropF.bottom.roundToInt(), ) - val windowAnimationDelay = + val interpolators: TransitionAnimator.Interpolators + val windowProgress: Float + + if (useSpring) { + val windowAnimationDelay: Float + val windowAnimationDuration: Float if (controller.isLaunching) { - TIMINGS.contentAfterFadeInDelay + windowAnimationDelay = SPRING_TIMINGS.contentAfterFadeInDelay + windowAnimationDuration = SPRING_TIMINGS.contentAfterFadeInDuration } else { - TIMINGS.contentBeforeFadeOutDelay + windowAnimationDelay = SPRING_TIMINGS.contentBeforeFadeOutDelay + windowAnimationDuration = SPRING_TIMINGS.contentBeforeFadeOutDuration } - val windowAnimationDuration = + + interpolators = SPRING_INTERPOLATORS + windowProgress = + TransitionAnimator.getProgress( + linearProgress, + windowAnimationDelay, + windowAnimationDuration, + ) + } else { + val windowAnimationDelay: Long + val windowAnimationDuration: Long if (controller.isLaunching) { - TIMINGS.contentAfterFadeInDuration + windowAnimationDelay = TIMINGS.contentAfterFadeInDelay + windowAnimationDuration = TIMINGS.contentAfterFadeInDuration } else { - TIMINGS.contentBeforeFadeOutDuration + windowAnimationDelay = TIMINGS.contentBeforeFadeOutDelay + windowAnimationDuration = TIMINGS.contentBeforeFadeOutDuration } - val windowProgress = - TransitionAnimator.getProgress( - TIMINGS, - linearProgress, - windowAnimationDelay, - windowAnimationDuration, - ) + + interpolators = INTERPOLATORS + windowProgress = + TransitionAnimator.getProgress( + TIMINGS, + linearProgress, + windowAnimationDelay, + windowAnimationDuration, + ) + } // The alpha of the opening window. If it opens above the expandable, then it should // fade in progressively. Otherwise, it should be fully opaque and will be progressively @@ -1197,12 +1577,12 @@ constructor( val alpha = if (controller.isBelowAnimatingWindow) { if (controller.isLaunching) { - INTERPOLATORS.contentAfterFadeInInterpolator.getInterpolation( + interpolators.contentAfterFadeInInterpolator.getInterpolation( windowProgress ) } else { 1 - - INTERPOLATORS.contentBeforeFadeOutInterpolator.getInterpolation( + interpolators.contentBeforeFadeOutInterpolator.getInterpolation( windowProgress ) } @@ -1216,6 +1596,7 @@ constructor( // especially important for lock screen animations, where the window is not clipped by // the shade. val cornerRadius = maxOf(state.topCornerRadius, state.bottomCornerRadius) / scale + val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(window.leash) .withAlpha(alpha) @@ -1223,11 +1604,15 @@ constructor( .withWindowCrop(windowCrop) .withCornerRadius(cornerRadius) .withVisibility(true) - .build() + if (transaction != null) params.withMergeTransaction(transaction) - transactionApplier.scheduleApply(params) + transactionApplier.scheduleApply(params.build()) } + // TODO(b/377643129): remote transitions have no way of identifying the navbar when + // converting to RemoteAnimationTargets (and in my testing it was never included in the + // transition at all). So this method is not used anymore. Remove or adapt once we fully + // convert to remote transitions. private fun applyStateToNavigationBar( navigationBar: RemoteAnimationTarget, state: TransitionAnimator.State, @@ -1362,9 +1747,17 @@ constructor( } /** Register [remoteTransition] with WM Shell using the given [filter]. */ - internal fun register(filter: TransitionFilter, remoteTransition: RemoteTransition) { + internal fun register( + filter: TransitionFilter, + remoteTransition: RemoteTransition, + includeTakeover: Boolean, + ) { shellTransitions?.registerRemote(filter, remoteTransition) iShellTransitions?.registerRemote(filter, remoteTransition) + if (includeTakeover) { + shellTransitions?.registerRemoteForTakeover(filter, remoteTransition) + iShellTransitions?.registerRemoteForTakeover(filter, remoteTransition) + } } /** Unregister [remoteTransition] from WM Shell. */ diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt index fdb4871423c3..de4bdbc284c4 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt @@ -38,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting import com.android.internal.dynamicanimation.animation.SpringAnimation import com.android.internal.dynamicanimation.animation.SpringForce import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary +import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived import java.util.concurrent.Executor import kotlin.math.abs import kotlin.math.max @@ -113,13 +114,26 @@ class TransitionAnimator( ) } - internal fun checkReturnAnimationFrameworkFlag() { - check(returnAnimationFrameworkLibrary()) { - "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag is " + - "disabled" + internal fun assertReturnAnimations() { + check(returnAnimationsEnabled()) { + "isLaunching cannot be false when the returnAnimationFrameworkLibrary flag " + + "is disabled" } } + internal fun returnAnimationsEnabled() = returnAnimationFrameworkLibrary() + + internal fun assertLongLivedReturnAnimations() { + check(longLivedReturnAnimationsEnabled()) { + "Long-lived registrations cannot be used when the " + + "returnAnimationFrameworkLibrary or the " + + "returnAnimationFrameworkLongLived flag are disabled" + } + } + + internal fun longLivedReturnAnimationsEnabled() = + returnAnimationFrameworkLibrary() && returnAnimationFrameworkLongLived() + internal fun WindowAnimationState.toTransitionState() = State().also { bounds?.let { b -> @@ -467,7 +481,8 @@ class TransitionAnimator( drawHole: Boolean = false, startVelocity: PointF? = null, ): Animation { - if (!controller.isLaunching || startVelocity != null) checkReturnAnimationFrameworkFlag() + if (!controller.isLaunching) assertReturnAnimations() + if (startVelocity != null) assertLongLivedReturnAnimations() // We add an extra layer with the same color as the dialog/app splash screen background // color, which is usually the same color of the app background. We first fade in this layer diff --git a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt index d31d7aa59489..71ec63c1666c 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/theme/PlatformTheme.kt @@ -63,6 +63,9 @@ private fun platformColorScheme(isDarkTheme: Boolean, context: Context): ColorSc return if (isDarkTheme) { dynamicDarkColorScheme(context) .copy( + inverseSurface = color(context, R.color.system_inverse_surface_dark), + inverseOnSurface = color(context, R.color.system_inverse_on_surface_dark), + inversePrimary = color(context, R.color.system_inverse_primary_dark), error = color(context, R.color.system_error_dark), onError = color(context, R.color.system_on_error_dark), errorContainer = color(context, R.color.system_error_container_dark), @@ -71,6 +74,9 @@ private fun platformColorScheme(isDarkTheme: Boolean, context: Context): ColorSc } else { dynamicLightColorScheme(context) .copy( + inverseSurface = color(context, R.color.system_inverse_surface_light), + inverseOnSurface = color(context, R.color.system_inverse_on_surface_light), + inversePrimary = color(context, R.color.system_inverse_primary_light), error = color(context, R.color.system_error_light), onError = color(context, R.color.system_on_error_light), errorContainer = color(context, R.color.system_error_container_light), diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt index de021a0677cf..737853b88f7a 100644 --- a/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt +++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/theme/PlatformThemeTest.kt @@ -89,7 +89,7 @@ class PlatformThemeTest { addValue( "inversePrimary", colorScheme.inversePrimary, - R.attr.materialColorPrimaryInverse, + R.attr.materialColorInversePrimary, ) addValue("secondary", colorScheme.secondary, R.attr.materialColorSecondary) addValue("onSecondary", colorScheme.onSecondary, R.attr.materialColorOnSecondary) @@ -131,12 +131,12 @@ class PlatformThemeTest { addValue( "inverseSurface", colorScheme.inverseSurface, - R.attr.materialColorSurfaceInverse, + R.attr.materialColorInverseSurface, ) addValue( "inverseOnSurface", colorScheme.inverseOnSurface, - R.attr.materialColorOnSurfaceInverse, + R.attr.materialColorInverseOnSurface, ) addValue("error", colorScheme.error, R.attr.materialColorError) addValue("onError", colorScheme.onError, R.attr.materialColorOnError) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt index 96e99b15363d..778d7e7f99b3 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContent.kt @@ -67,6 +67,7 @@ constructor( dialogFactory = dialogFactory, widgetSection = widgetSection, modifier = Modifier.element(Communal.Elements.Grid), + sceneScope = this@Content, ) } with(lockSection) { 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 df1185cb1a6d..5b1203fa17c9 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 @@ -163,6 +163,7 @@ import androidx.compose.ui.zIndex import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.window.layout.WindowMetricsCalculator import com.android.compose.animation.Easings.Emphasized +import com.android.compose.animation.scene.SceneScope import com.android.compose.modifiers.thenIf import com.android.compose.ui.graphics.painter.rememberDrawablePainter import com.android.internal.R.dimen.system_app_widget_background_radius @@ -186,7 +187,9 @@ import com.android.systemui.communal.util.DensityUtils.Companion.adjustedDp import com.android.systemui.communal.widgets.SmartspaceAppWidgetHostView import com.android.systemui.communal.widgets.WidgetConfigurator import com.android.systemui.lifecycle.rememberViewModel +import com.android.systemui.media.controls.ui.composable.MediaCarousel import com.android.systemui.res.R +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.statusbar.phone.SystemUIDialogFactory import kotlin.math.max import kotlin.math.min @@ -205,6 +208,7 @@ fun CommunalHub( widgetConfigurator: WidgetConfigurator? = null, onOpenWidgetPicker: (() -> Unit)? = null, onEditDone: (() -> Unit)? = null, + sceneScope: SceneScope? = null, ) { val communalContent by viewModel.communalContent.collectAsStateWithLifecycle(initialValue = emptyList()) @@ -414,6 +418,7 @@ fun CommunalHub( widgetConfigurator = widgetConfigurator, interactionHandler = interactionHandler, widgetSection = widgetSection, + sceneScope = sceneScope, ) } } @@ -735,6 +740,7 @@ private fun BoxScope.CommunalHubLazyGrid( widgetConfigurator: WidgetConfigurator?, interactionHandler: RemoteViews.InteractionHandler?, widgetSection: CommunalAppWidgetSection, + sceneScope: SceneScope?, ) { var gridModifier = Modifier.align(Alignment.TopStart).onGloballyPositioned { setGridCoordinates(it) } @@ -871,6 +877,7 @@ private fun BoxScope.CommunalHubLazyGrid( interactionHandler = interactionHandler, widgetSection = widgetSection, resizeableItemFrameViewModel = resizeableItemFrameViewModel, + sceneScope = sceneScope, ) } } @@ -1095,6 +1102,7 @@ private fun CommunalContent( interactionHandler: RemoteViews.InteractionHandler?, widgetSection: CommunalAppWidgetSection, resizeableItemFrameViewModel: ResizeableItemFrameViewModel, + sceneScope: SceneScope? = null, ) { when (model) { is CommunalContentModel.WidgetContent.Widget -> @@ -1118,7 +1126,7 @@ private fun CommunalContent( is CommunalContentModel.CtaTileInViewMode -> CtaTileInViewModeContent(viewModel, modifier) is CommunalContentModel.Smartspace -> SmartspaceContent(interactionHandler, model, modifier) is CommunalContentModel.Tutorial -> TutorialContent(modifier) - is CommunalContentModel.Umo -> Umo(viewModel, modifier) + is CommunalContentModel.Umo -> Umo(viewModel, sceneScope, modifier) } } @@ -1529,7 +1537,25 @@ private fun TutorialContent(modifier: Modifier = Modifier) { } @Composable -private fun Umo(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier) { +private fun Umo( + viewModel: BaseCommunalViewModel, + sceneScope: SceneScope?, + modifier: Modifier = Modifier, +) { + if (SceneContainerFlag.isEnabled && sceneScope != null) { + sceneScope.MediaCarousel( + modifier = modifier.fillMaxSize(), + isVisible = true, + mediaHost = viewModel.mediaHost, + carouselController = viewModel.mediaCarouselController, + ) + } else { + UmoLegacy(viewModel, modifier) + } +} + +@Composable +private fun UmoLegacy(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier) { AndroidView( modifier = modifier.pointerInput(Unit) { 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 d546a5db495e..9de7a5d659ae 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 @@ -16,6 +16,7 @@ import com.android.systemui.scene.ui.composable.transitions.bouncerToLockscreenP import com.android.systemui.scene.ui.composable.transitions.communalToBouncerTransition import com.android.systemui.scene.ui.composable.transitions.communalToShadeTransition import com.android.systemui.scene.ui.composable.transitions.dreamToBouncerTransition +import com.android.systemui.scene.ui.composable.transitions.dreamToCommunalTransition import com.android.systemui.scene.ui.composable.transitions.dreamToGoneTransition import com.android.systemui.scene.ui.composable.transitions.dreamToShadeTransition import com.android.systemui.scene.ui.composable.transitions.goneToQuickSettingsTransition @@ -58,6 +59,7 @@ val SceneContainerTransitions = transitions { from(Scenes.Bouncer, to = Scenes.Gone) { bouncerToGoneTransition() } from(Scenes.Dream, to = Scenes.Bouncer) { dreamToBouncerTransition() } + from(Scenes.Dream, to = Scenes.Communal) { dreamToCommunalTransition() } from(Scenes.Dream, to = Scenes.Gone) { dreamToGoneTransition() } from(Scenes.Dream, to = Scenes.Shade) { dreamToShadeTransition() } from(Scenes.Gone, to = Scenes.Shade) { goneToShadeTransition() } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToCommunalTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToCommunalTransition.kt new file mode 100644 index 000000000000..93c10b6224ab --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromDreamToCommunalTransition.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.scene.ui.composable.transitions + +import androidx.compose.animation.core.tween +import com.android.compose.animation.scene.Edge +import com.android.compose.animation.scene.TransitionBuilder +import com.android.systemui.communal.ui.compose.AllElements +import com.android.systemui.communal.ui.compose.Communal + +fun TransitionBuilder.dreamToCommunalTransition() { + spec = tween(durationMillis = 1000) + + // Translate communal hub grid from the end direction. + translate(Communal.Elements.Grid, Edge.End) + + // Fade all communal hub elements. + timestampRange(startMillis = 167, endMillis = 334) { fade(AllElements) } +} 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 71fa6c9e567a..ce7a85b19fb4 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 @@ -19,11 +19,8 @@ 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.media.controls.ui.composable.MediaCarousel import com.android.systemui.notifications.ui.composable.Notifications import com.android.systemui.qs.ui.composable.QuickSettings @@ -31,24 +28,17 @@ 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, -) { +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 - } - } + distance = UserActionDistance { fromContent, _, _ -> + val fromContentSize = checkNotNull(fromContent.targetSize()) + fromContentSize.height.toFloat() * 2 / 3f + } fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) } 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 index 1486ea7d53b5..1f7a7380bbc6 100644 --- 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 @@ -19,35 +19,25 @@ 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.lockscreenToSplitShadeTransition( - durationScale: Double = 1.0, -) { +fun TransitionBuilder.lockscreenToSplitShadeTransition(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 - } - } + distance = UserActionDistance { fromContent, _, _ -> + val fromContentSize = checkNotNull(fromContent.targetSize()) + fromContentSize.height.toFloat() * 2 / 3f + } fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt index 8cd357ef92a5..ba1972fbcc5a 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt @@ -1,46 +1,36 @@ package com.android.systemui.scene.ui.composable.transitions import androidx.compose.animation.core.tween -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.ui.unit.IntSize import com.android.compose.animation.scene.Edge 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.scene.shared.model.Scenes import com.android.systemui.shade.ui.composable.ShadeHeader import kotlin.time.Duration.Companion.milliseconds -fun TransitionBuilder.shadeToQuickSettingsTransition( - durationScale: Double = 1.0, -) { +fun TransitionBuilder.shadeToQuickSettingsTransition(durationScale: Double = 1.0) { spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt()) - distance = - object : UserActionDistance { - override fun UserActionDistanceScope.absoluteDistance( - fromSceneSize: IntSize, - orientation: Orientation, - ): Float { - val distance = - Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y - ?: return 0f - return fromSceneSize.height - distance - } - } + distance = UserActionDistance { fromContent, _, _ -> + val distance = + Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y + ?: return@UserActionDistance 0f + val fromContentSize = checkNotNull(fromContent.targetSize()) + fromContentSize.height - distance + } translate(Notifications.Elements.NotificationScrim, Edge.Bottom) timestampRange(endMillis = 83) { fade(QuickSettings.Elements.FooterActions) } translate( ShadeHeader.Elements.CollapsedContentStart, - y = ShadeHeader.Dimensions.CollapsedHeight + y = ShadeHeader.Dimensions.CollapsedHeight, ) translate(ShadeHeader.Elements.CollapsedContentEnd, y = ShadeHeader.Dimensions.CollapsedHeight) translate( ShadeHeader.Elements.ExpandedContent, - y = -(ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight) + y = -(ShadeHeader.Dimensions.ExpandedHeight - ShadeHeader.Dimensions.CollapsedHeight), ) translate(ShadeHeader.Elements.ShadeCarrierGroup, y = -ShadeHeader.Dimensions.CollapsedHeight) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt index de76f708c1c7..d35537a74c85 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToBouncerTransition.kt @@ -28,8 +28,9 @@ private const val TO_BOUNCER_SWIPE_DISTANCE_FRACTION = 0.5f fun TransitionBuilder.toBouncerTransition() { spec = tween(durationMillis = 500) - distance = UserActionDistance { fromSceneSize, _ -> - fromSceneSize.height * TO_BOUNCER_SWIPE_DISTANCE_FRACTION + distance = UserActionDistance { fromContent, _, _ -> + val fromContentSize = checkNotNull(fromContent.targetSize()) + fromContentSize.height * TO_BOUNCER_SWIPE_DISTANCE_FRACTION } translate(Bouncer.Elements.Content, y = 300.dp) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt index 55fa6ad94ed3..e78bc6afcc4f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt @@ -33,7 +33,10 @@ fun TransitionBuilder.toQuickSettingsShadeTransition(durationScale: Double = 1.0 stiffness = Spring.StiffnessMediumLow, visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold, ) - distance = UserActionDistance { fromSceneSize, _ -> fromSceneSize.height.toFloat() * 2 / 3f } + distance = UserActionDistance { fromContent, _, _ -> + val fromContentSize = checkNotNull(fromContent.targetSize()) + fromContentSize.height.toFloat() * 2 / 3f + } translate(OverlayShade.Elements.Panel, Edge.Top) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt index b677dff2dcf9..bfae4897dc68 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToShadeTransition.kt @@ -19,12 +19,9 @@ 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.Edge 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.media.controls.ui.composable.MediaCarousel import com.android.systemui.notifications.ui.composable.Notifications import com.android.systemui.qs.ui.composable.QuickSettings @@ -33,24 +30,16 @@ import com.android.systemui.shade.ui.composable.Shade import com.android.systemui.shade.ui.composable.ShadeHeader import kotlin.time.Duration.Companion.milliseconds -fun TransitionBuilder.toShadeTransition( - durationScale: Double = 1.0, -) { +fun TransitionBuilder.toShadeTransition(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 Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y ?: 0f - } - } + distance = UserActionDistance { _, _, _ -> + Notifications.Elements.NotificationScrim.targetOffset(Scenes.Shade)?.y ?: 0f + } fractionRange(start = .58f) { fade(ShadeHeader.Elements.Clock) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt index 352d29e21987..74896482be88 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/SingleShadeMeasurePolicy.kt @@ -25,7 +25,6 @@ import androidx.compose.ui.layout.Placeable import androidx.compose.ui.layout.layoutId import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.offset -import androidx.compose.ui.util.fastFirst import androidx.compose.ui.util.fastFirstOrNull import com.android.systemui.shade.ui.composable.SingleShadeMeasurePolicy.LayoutId import kotlin.math.max @@ -60,18 +59,20 @@ class SingleShadeMeasurePolicy( val shadeHeaderPlaceable = measurables - .fastFirst { it.layoutId == LayoutId.ShadeHeader } - .measure(constraintsWithCutout) + .fastFirstOrNull { it.layoutId == LayoutId.ShadeHeader } + ?.measure(constraintsWithCutout) val mediaPlaceable = measurables .fastFirstOrNull { it.layoutId == LayoutId.Media } ?.measure(applyMediaConstraints(constraintsWithCutout, isMediaInRow)) val quickSettingsPlaceable = measurables - .fastFirst { it.layoutId == LayoutId.QuickSettings } - .measure(constraintsWithCutout) + .fastFirstOrNull { it.layoutId == LayoutId.QuickSettings } + ?.measure(constraintsWithCutout) val notificationsPlaceable = - measurables.fastFirst { it.layoutId == LayoutId.Notifications }.measure(constraints) + measurables + .fastFirstOrNull { it.layoutId == LayoutId.Notifications } + ?.measure(constraints) val notificationsTop = calculateNotificationsTop( @@ -84,23 +85,25 @@ class SingleShadeMeasurePolicy( onNotificationsTopChanged(notificationsTop) return layout(constraints.maxWidth, constraints.maxHeight) { - shadeHeaderPlaceable.placeRelative(x = insetsLeft, y = insetsTop) - quickSettingsPlaceable.placeRelative( + shadeHeaderPlaceable?.placeRelative(x = insetsLeft, y = insetsTop) + val statusBarHeaderHeight = shadeHeaderPlaceable?.height ?: 0 + quickSettingsPlaceable?.placeRelative( x = insetsLeft, - y = insetsTop + shadeHeaderPlaceable.height, + y = insetsTop + statusBarHeaderHeight, ) - if (mediaPlaceable != null) + if (mediaPlaceable != null) { + val quickSettingsHeight = quickSettingsPlaceable?.height ?: 0 + if (isMediaInRow) { // mediaPlaceable height ranges from 0 to qsHeight. We want it to be centered // vertically when it's smaller than the QS - val mediaCenteringOffset = - (quickSettingsPlaceable.height - mediaPlaceable.height) / 2 + val mediaCenteringOffset = (quickSettingsHeight - mediaPlaceable.height) / 2 mediaPlaceable.placeRelative( x = insetsLeft + constraintsWithCutout.maxWidth / 2, y = insetsTop + - shadeHeaderPlaceable.height + + statusBarHeaderHeight + mediaCenteringOffset + mediaOffset(), zIndex = mediaZIndex(), @@ -108,30 +111,34 @@ class SingleShadeMeasurePolicy( } else { mediaPlaceable.placeRelative( x = insetsLeft, - y = insetsTop + shadeHeaderPlaceable.height + quickSettingsPlaceable.height, + y = insetsTop + statusBarHeaderHeight + quickSettingsHeight, zIndex = mediaZIndex(), ) } + } // Notifications don't need to accommodate for horizontal insets - notificationsPlaceable.placeRelative(x = 0, y = notificationsTop) + notificationsPlaceable?.placeRelative(x = 0, y = notificationsTop) } } private fun calculateNotificationsTop( - statusBarHeaderPlaceable: Placeable, - quickSettingsPlaceable: Placeable, + statusBarHeaderPlaceable: Placeable?, + quickSettingsPlaceable: Placeable?, mediaPlaceable: Placeable?, insetsTop: Int, isMediaInRow: Boolean, ): Int { val mediaHeight = mediaPlaceable?.height ?: 0 + val statusBarHeaderHeight = statusBarHeaderPlaceable?.height ?: 0 + val quickSettingsHeight = quickSettingsPlaceable?.height ?: 0 + return insetsTop + - statusBarHeaderPlaceable.height + + statusBarHeaderHeight + if (isMediaInRow) { - max(quickSettingsPlaceable.height, mediaHeight) + max(quickSettingsHeight, mediaHeight) } else { - quickSettingsPlaceable.height + mediaHeight + quickSettingsHeight + mediaHeight } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt index 163f4b36f472..78e605601b76 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/statusbar/phone/SystemUIDialogFactoryExt.kt @@ -307,6 +307,6 @@ private fun draggableTopPadding(): Dp { private object DraggableBottomSheet { val DefaultTopPadding = 64.dp - val LargeScreenTopPadding = 72.dp + val LargeScreenTopPadding = 56.dp val MaxWidth = 640.dp } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt index 44f60cb6f0a6..eb2a01632095 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt @@ -350,8 +350,7 @@ internal class ElementNode( val placeInThisContent = elementContentWhenIdle( layoutImpl, - currentState.currentScene, - currentState.currentOverlays, + currentState, isInContent = { it in element.stateByContent }, ) == content.key @@ -639,20 +638,11 @@ internal inline fun elementState( internal inline fun elementContentWhenIdle( layoutImpl: SceneTransitionLayoutImpl, - idle: TransitionState.Idle, - isInContent: (ContentKey) -> Boolean, -): ContentKey { - val currentScene = idle.currentScene - val overlays = idle.currentOverlays - return elementContentWhenIdle(layoutImpl, currentScene, overlays, isInContent) -} - -private inline fun elementContentWhenIdle( - layoutImpl: SceneTransitionLayoutImpl, - currentScene: SceneKey, - overlays: Set<OverlayKey>, + currentState: TransitionState, isInContent: (ContentKey) -> Boolean, ): ContentKey { + val currentScene = currentState.currentScene + val overlays = currentState.currentOverlays if (overlays.isEmpty()) { return currentScene } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt index c790ff03aef1..509a16c5a704 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt @@ -188,7 +188,9 @@ private fun shouldComposeMovableElement( return when ( val elementState = movableElementState(element, layoutImpl.state.transitionStates) ) { - null -> false + null -> + movableElementContentWhenIdle(layoutImpl, element, layoutImpl.state.transitionState) == + content is TransitionState.Idle -> movableElementContentWhenIdle(layoutImpl, element, elementState) == content is TransitionState.Transition -> { @@ -217,7 +219,7 @@ private fun movableElementState( private fun movableElementContentWhenIdle( layoutImpl: SceneTransitionLayoutImpl, element: MovableElementKey, - elementState: TransitionState.Idle, + elementState: TransitionState, ): ContentKey { val contents = element.contentPicker.contents return elementContentWhenIdle(layoutImpl, elementState, isInContent = { contents.contains(it) }) diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt index dbf7d7b29834..d3ddb5003469 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt @@ -637,8 +637,8 @@ sealed class UserActionResult( fun interface UserActionDistance { /** - * Return the **absolute** distance of the user action given the size of the scene we are - * animating from and the [orientation]. + * Return the **absolute** distance of the user action when going from [fromContent] to + * [toContent] in the given [orientation]. * * Note: This function will be called for each drag event until it returns a value > 0f. This * for instance allows you to return 0f or a negative value until the first layout pass of a @@ -646,7 +646,8 @@ fun interface UserActionDistance { * transitioning to when computing this absolute distance. */ fun UserActionDistanceScope.absoluteDistance( - fromSceneSize: IntSize, + fromContent: ContentKey, + toContent: ContentKey, orientation: Orientation, ): Float } @@ -656,7 +657,8 @@ interface UserActionDistanceScope : Density, ElementStateScope /** The user action has a fixed [absoluteDistance]. */ class FixedDistance(private val distance: Dp) : UserActionDistance { override fun UserActionDistanceScope.absoluteDistance( - fromSceneSize: IntSize, + fromContent: ContentKey, + toContent: ContentKey, orientation: Orientation, ): Float = distance.toPx() } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt index 7eb5a3f8b362..3bf2ed50b709 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt @@ -267,11 +267,12 @@ internal class MutableSceneTransitionLayoutStateImpl( private set /** - * The flattened list of [SharedElementTransformation] within all the transitions in + * The flattened list of [SharedElementTransformation.Factory] within all the transitions in * [transitionStates]. */ - private val transformationsWithElevation: List<SharedElementTransformation> by derivedStateOf { - transformationsWithElevation(transitionStates) + private val transformationFactoriesWithElevation: + List<SharedElementTransformation.Factory> by derivedStateOf { + transformationFactoriesWithElevation(transitionStates) } override val currentScene: SceneKey @@ -355,6 +356,12 @@ internal class MutableSceneTransitionLayoutStateImpl( override suspend fun startTransition(transition: TransitionState.Transition, chain: Boolean) { checkThread() + // Prepare the transition before starting it. This is outside of the try/finally block on + // purpose because preparing a transition might throw an exception (e.g. if we find multiple + // specs matching this transition), in which case we want to throw that exception here + // before even starting the transition. + prepareTransitionBeforeStarting(transition) + try { // Start the transition. startTransitionInternal(transition, chain) @@ -366,7 +373,7 @@ internal class MutableSceneTransitionLayoutStateImpl( } } - private fun startTransitionInternal(transition: TransitionState.Transition, chain: Boolean) { + private fun prepareTransitionBeforeStarting(transition: TransitionState.Transition) { // Set the current scene and overlays on the transition. val currentState = transitionState transition.currentSceneWhenTransitionStarted = currentState.currentScene @@ -394,7 +401,9 @@ internal class MutableSceneTransitionLayoutStateImpl( } else { transition.updateOverscrollSpecs(fromSpec = null, toSpec = null) } + } + private fun startTransitionInternal(transition: TransitionState.Transition, chain: Boolean) { when (val currentState = transitionStates.last()) { is TransitionState.Idle -> { // Replace [Idle] by [transition]. @@ -692,22 +701,23 @@ internal class MutableSceneTransitionLayoutStateImpl( animate() } - private fun transformationsWithElevation( + private fun transformationFactoriesWithElevation( transitionStates: List<TransitionState> - ): List<SharedElementTransformation> { + ): List<SharedElementTransformation.Factory> { return buildList { transitionStates.fastForEach { state -> if (state !is TransitionState.Transition) { return@fastForEach } - state.transformationSpec.transformations.fastForEach { transformationWithRange -> - val transformation = transformationWithRange.transformation + state.transformationSpec.transformationMatchers.fastForEach { transformationMatcher + -> + val factory = transformationMatcher.factory if ( - transformation is SharedElementTransformation && - transformation.elevateInContent != null + factory is SharedElementTransformation.Factory && + factory.elevateInContent != null ) { - add(transformation) + add(factory) } } } @@ -722,10 +732,10 @@ internal class MutableSceneTransitionLayoutStateImpl( * necessary, for performance. */ internal fun isElevationPossible(content: ContentKey, element: ElementKey?): Boolean { - if (transformationsWithElevation.isEmpty()) return false - return transformationsWithElevation.fastAny { transformation -> - transformation.elevateInContent == content && - (element == null || transformation.matcher.matches(element, content)) + if (transformationFactoriesWithElevation.isEmpty()) return false + return transformationFactoriesWithElevation.fastAny { factory -> + factory.elevateInContent == content && + (element == null || factory.matcher.matches(element, content)) } } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt index 569593c3eb59..8df3f2d932b3 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt @@ -26,17 +26,9 @@ import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.util.fastForEach import com.android.compose.animation.scene.content.state.TransitionState -import com.android.compose.animation.scene.transformation.CustomAlphaTransformation -import com.android.compose.animation.scene.transformation.CustomOffsetTransformation -import com.android.compose.animation.scene.transformation.CustomScaleTransformation -import com.android.compose.animation.scene.transformation.CustomSizeTransformation -import com.android.compose.animation.scene.transformation.InterpolatedAlphaTransformation -import com.android.compose.animation.scene.transformation.InterpolatedOffsetTransformation -import com.android.compose.animation.scene.transformation.InterpolatedScaleTransformation -import com.android.compose.animation.scene.transformation.InterpolatedSizeTransformation import com.android.compose.animation.scene.transformation.PropertyTransformation import com.android.compose.animation.scene.transformation.SharedElementTransformation -import com.android.compose.animation.scene.transformation.Transformation +import com.android.compose.animation.scene.transformation.TransformationMatcher import com.android.compose.animation.scene.transformation.TransformationWithRange /** The transitions configuration of a [SceneTransitionLayout]. */ @@ -169,7 +161,7 @@ internal constructor( } /** The definition of a transition between [from] and [to]. */ -interface TransitionSpec { +internal interface TransitionSpec { /** The key of this [TransitionSpec]. */ val key: TransitionKey? @@ -209,7 +201,7 @@ interface TransitionSpec { fun previewTransformationSpec(transition: TransitionState.Transition): TransformationSpec? } -interface TransformationSpec { +internal interface TransformationSpec { /** * The [AnimationSpec] used to animate the associated transition progress from `0` to `1` when * the transition is triggered (i.e. it is not gesture-based). @@ -232,8 +224,8 @@ interface TransformationSpec { */ val distance: UserActionDistance? - /** The list of [Transformation] applied to elements during this transition. */ - val transformations: List<TransformationWithRange<*>> + /** The list of [TransformationMatcher] applied to elements during this transformation. */ + val transformationMatchers: List<TransformationMatcher> companion object { internal val Empty = @@ -241,7 +233,7 @@ interface TransformationSpec { progressSpec = snap(), swipeSpec = null, distance = null, - transformations = emptyList(), + transformationMatchers = emptyList(), ) internal val EmptyProvider = { _: TransitionState.Transition -> Empty } } @@ -272,7 +264,14 @@ internal class TransitionSpecImpl( progressSpec = reverse.progressSpec, swipeSpec = reverse.swipeSpec, distance = reverse.distance, - transformations = reverse.transformations.map { it.reversed() }, + transformationMatchers = + reverse.transformationMatchers.map { + TransformationMatcher( + matcher = it.matcher, + factory = it.factory, + range = it.range?.reversed(), + ) + }, ) }, ) @@ -288,7 +287,7 @@ internal class TransitionSpecImpl( } /** The definition of the overscroll behavior of the [content]. */ -interface OverscrollSpec { +internal interface OverscrollSpec { /** The scene we are over scrolling. */ val content: ContentKey @@ -325,7 +324,7 @@ internal class TransformationSpecImpl( override val progressSpec: AnimationSpec<Float>, override val swipeSpec: SpringSpec<Float>?, override val distance: UserActionDistance?, - override val transformations: List<TransformationWithRange<*>>, + override val transformationMatchers: List<TransformationMatcher>, ) : TransformationSpec { private val cache = mutableMapOf<ElementKey, MutableMap<ContentKey, ElementTransformations>>() @@ -335,7 +334,7 @@ internal class TransformationSpecImpl( .getOrPut(content) { computeTransformations(element, content) } } - /** Filter [transformations] to compute the [ElementTransformations] of [element]. */ + /** Filter [transformationMatchers] to compute the [ElementTransformations] of [element]. */ private fun computeTransformations( element: ElementKey, content: ContentKey, @@ -346,46 +345,55 @@ internal class TransformationSpecImpl( var drawScale: TransformationWithRange<PropertyTransformation<Scale>>? = null var alpha: TransformationWithRange<PropertyTransformation<Float>>? = null - transformations.fastForEach { transformationWithRange -> - val transformation = transformationWithRange.transformation - if (!transformation.matcher.matches(element, content)) { + transformationMatchers.fastForEach { transformationMatcher -> + if (!transformationMatcher.matcher.matches(element, content)) { return@fastForEach } - when (transformation) { - is SharedElementTransformation -> { - throwIfNotNull(shared, element, name = "shared") - shared = - transformationWithRange - as TransformationWithRange<SharedElementTransformation> + val transformation = transformationMatcher.factory.create() + val property = + when (transformation) { + is SharedElementTransformation -> { + throwIfNotNull(shared, element, name = "shared") + shared = + TransformationWithRange(transformation, transformationMatcher.range) + return@fastForEach + } + is PropertyTransformation<*> -> transformation.property } - is InterpolatedOffsetTransformation, - is CustomOffsetTransformation -> { + + when (property) { + is PropertyTransformation.Property.Offset -> { throwIfNotNull(offset, element, name = "offset") offset = - transformationWithRange - as TransformationWithRange<PropertyTransformation<Offset>> + TransformationWithRange( + transformation as PropertyTransformation<Offset>, + transformationMatcher.range, + ) } - is InterpolatedSizeTransformation, - is CustomSizeTransformation -> { + is PropertyTransformation.Property.Size -> { throwIfNotNull(size, element, name = "size") size = - transformationWithRange - as TransformationWithRange<PropertyTransformation<IntSize>> + TransformationWithRange( + transformation as PropertyTransformation<IntSize>, + transformationMatcher.range, + ) } - is InterpolatedScaleTransformation, - is CustomScaleTransformation -> { + is PropertyTransformation.Property.Scale -> { throwIfNotNull(drawScale, element, name = "drawScale") drawScale = - transformationWithRange - as TransformationWithRange<PropertyTransformation<Scale>> + TransformationWithRange( + transformation as PropertyTransformation<Scale>, + transformationMatcher.range, + ) } - is InterpolatedAlphaTransformation, - is CustomAlphaTransformation -> { + is PropertyTransformation.Property.Alpha -> { throwIfNotNull(alpha, element, name = "alpha") alpha = - transformationWithRange - as TransformationWithRange<PropertyTransformation<Float>> + TransformationWithRange( + transformation as PropertyTransformation<Float>, + transformationMatcher.range, + ) } } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt index f0043e1e89b0..dbfeb5cd0168 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SwipeAnimation.kt @@ -24,7 +24,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue -import androidx.compose.ui.unit.IntSize import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.content.state.TransitionState.HasOverscrollProperties.Companion.DistanceUnspecified import kotlin.math.absoluteValue @@ -66,8 +65,9 @@ internal fun createSwipeAnimation( val absoluteDistance = with(animation.contentTransition.transformationSpec.distance ?: DefaultSwipeDistance) { layoutImpl.userActionDistanceScope.absoluteDistance( - layoutImpl.content(animation.fromContent).targetSize, - orientation, + fromContent = animation.fromContent, + toContent = animation.toContent, + orientation = orientation, ) } @@ -475,12 +475,14 @@ internal class SwipeAnimation<T : ContentKey>( private object DefaultSwipeDistance : UserActionDistance { override fun UserActionDistanceScope.absoluteDistance( - fromSceneSize: IntSize, + fromContent: ContentKey, + toContent: ContentKey, orientation: Orientation, ): Float { + val fromContentSize = checkNotNull(fromContent.targetSize()) return when (orientation) { - Orientation.Horizontal -> fromSceneSize.width - Orientation.Vertical -> fromSceneSize.height + Orientation.Horizontal -> fromContentSize.width + Orientation.Vertical -> fromContentSize.height }.toFloat() } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt index 1fdfca9d9509..48f08a7086d6 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDsl.kt @@ -26,7 +26,7 @@ import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.content.state.TransitionState -import com.android.compose.animation.scene.transformation.CustomPropertyTransformation +import com.android.compose.animation.scene.transformation.Transformation import kotlin.math.tanh /** Define the [transitions][SceneTransitions] to be used with a [SceneTransitionLayout]. */ @@ -76,7 +76,7 @@ interface SceneTransitionsBuilder { preview: (TransitionBuilder.() -> Unit)? = null, reversePreview: (TransitionBuilder.() -> Unit)? = null, builder: TransitionBuilder.() -> Unit = {}, - ): TransitionSpec + ) /** * Define the animation to be played when transitioning [from] the specified content. For the @@ -102,7 +102,7 @@ interface SceneTransitionsBuilder { preview: (TransitionBuilder.() -> Unit)? = null, reversePreview: (TransitionBuilder.() -> Unit)? = null, builder: TransitionBuilder.() -> Unit = {}, - ): TransitionSpec + ) /** * Define the animation to be played when the [content] is overscrolled in the given @@ -115,13 +115,13 @@ interface SceneTransitionsBuilder { content: ContentKey, orientation: Orientation, builder: OverscrollBuilder.() -> Unit, - ): OverscrollSpec + ) /** * Prevents overscroll the [content] in the given [orientation], allowing ancestors to * eventually consume the remaining gesture. */ - fun overscrollDisabled(content: ContentKey, orientation: Orientation): OverscrollSpec + fun overscrollDisabled(content: ContentKey, orientation: Orientation) } interface BaseTransitionBuilder : PropertyTransformationBuilder { @@ -529,15 +529,8 @@ interface PropertyTransformationBuilder { anchorHeight: Boolean = true, ) - /** - * Apply a [CustomPropertyTransformation] to one or more elements. - * - * @see com.android.compose.animation.scene.transformation.CustomSizeTransformation - * @see com.android.compose.animation.scene.transformation.CustomOffsetTransformation - * @see com.android.compose.animation.scene.transformation.CustomAlphaTransformation - * @see com.android.compose.animation.scene.transformation.CustomScaleTransformation - */ - fun transformation(transformation: CustomPropertyTransformation<*>) + /** Apply a [transformation] to the element(s) matching [matcher]. */ + fun transformation(matcher: ElementMatcher, transformation: Transformation.Factory) } /** This converter lets you change a linear progress into a function of your choice. */ diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt index 79f8cd47d07d..6742b3200ac4 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/TransitionDslImpl.kt @@ -30,7 +30,6 @@ import androidx.compose.ui.unit.Dp import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.transformation.AnchoredSize import com.android.compose.animation.scene.transformation.AnchoredTranslate -import com.android.compose.animation.scene.transformation.CustomPropertyTransformation import com.android.compose.animation.scene.transformation.DrawScale import com.android.compose.animation.scene.transformation.EdgeTranslate import com.android.compose.animation.scene.transformation.Fade @@ -38,8 +37,8 @@ import com.android.compose.animation.scene.transformation.OverscrollTranslate import com.android.compose.animation.scene.transformation.ScaleSize import com.android.compose.animation.scene.transformation.SharedElementTransformation import com.android.compose.animation.scene.transformation.Transformation +import com.android.compose.animation.scene.transformation.TransformationMatcher import com.android.compose.animation.scene.transformation.TransformationRange -import com.android.compose.animation.scene.transformation.TransformationWithRange import com.android.compose.animation.scene.transformation.Translate internal fun transitionsImpl(builder: SceneTransitionsBuilder.() -> Unit): SceneTransitions { @@ -67,8 +66,8 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { preview: (TransitionBuilder.() -> Unit)?, reversePreview: (TransitionBuilder.() -> Unit)?, builder: TransitionBuilder.() -> Unit, - ): TransitionSpec { - return transition(from = null, to = to, key = key, preview, reversePreview, builder) + ) { + transition(from = null, to = to, key = key, preview, reversePreview, builder) } override fun from( @@ -78,25 +77,25 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { preview: (TransitionBuilder.() -> Unit)?, reversePreview: (TransitionBuilder.() -> Unit)?, builder: TransitionBuilder.() -> Unit, - ): TransitionSpec { - return transition(from = from, to = to, key = key, preview, reversePreview, builder) + ) { + transition(from = from, to = to, key = key, preview, reversePreview, builder) } override fun overscroll( content: ContentKey, orientation: Orientation, builder: OverscrollBuilder.() -> Unit, - ): OverscrollSpec { + ) { val impl = OverscrollBuilderImpl().apply(builder) - check(impl.transformations.isNotEmpty()) { + check(impl.transformationMatchers.isNotEmpty()) { "This method does not allow empty transformations. " + "Use overscrollDisabled($content, $orientation) instead." } - return overscrollSpec(content, orientation, impl) + overscrollSpec(content, orientation, impl) } - override fun overscrollDisabled(content: ContentKey, orientation: Orientation): OverscrollSpec { - return overscrollSpec(content, orientation, OverscrollBuilderImpl()) + override fun overscrollDisabled(content: ContentKey, orientation: Orientation) { + overscrollSpec(content, orientation, OverscrollBuilderImpl()) } private fun overscrollSpec( @@ -113,7 +112,7 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { progressSpec = snap(), swipeSpec = null, distance = impl.distance, - transformations = impl.transformations, + transformationMatchers = impl.transformationMatchers, ), progressConverter = impl.progressConverter, ) @@ -138,7 +137,7 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { progressSpec = impl.spec, swipeSpec = impl.swipeSpec, distance = impl.distance, - transformations = impl.transformations, + transformationMatchers = impl.transformationMatchers, ) } @@ -158,7 +157,7 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { } internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder { - val transformations = mutableListOf<TransformationWithRange<*>>() + val transformationMatchers = mutableListOf<TransformationMatcher>() private var range: TransformationRange? = null protected var reversed = false override var distance: UserActionDistance? = null @@ -174,23 +173,31 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder { range = null } - protected fun addTransformation(transformation: Transformation) { - val transformationWithRange = TransformationWithRange(transformation, range) - transformations.add( - if (reversed) { - transformationWithRange.reversed() - } else { - transformationWithRange - } + protected fun addTransformation( + matcher: ElementMatcher, + transformation: Transformation.Factory, + ) { + transformationMatchers.add( + TransformationMatcher( + matcher, + transformation, + range?.let { range -> + if (reversed) { + range.reversed() + } else { + range + } + }, + ) ) } override fun fade(matcher: ElementMatcher) { - addTransformation(Fade(matcher)) + addTransformation(matcher, Fade.Factory) } override fun translate(matcher: ElementMatcher, x: Dp, y: Dp) { - addTransformation(Translate(matcher, x, y)) + addTransformation(matcher, Translate.Factory(x, y)) } override fun translate( @@ -198,19 +205,19 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder { edge: Edge, startsOutsideLayoutBounds: Boolean, ) { - addTransformation(EdgeTranslate(matcher, edge, startsOutsideLayoutBounds)) + addTransformation(matcher, EdgeTranslate.Factory(edge, startsOutsideLayoutBounds)) } override fun anchoredTranslate(matcher: ElementMatcher, anchor: ElementKey) { - addTransformation(AnchoredTranslate(matcher, anchor)) + addTransformation(matcher, AnchoredTranslate.Factory(anchor)) } override fun scaleSize(matcher: ElementMatcher, width: Float, height: Float) { - addTransformation(ScaleSize(matcher, width, height)) + addTransformation(matcher, ScaleSize.Factory(width, height)) } override fun scaleDraw(matcher: ElementMatcher, scaleX: Float, scaleY: Float, pivot: Offset) { - addTransformation(DrawScale(matcher, scaleX, scaleY, pivot)) + addTransformation(matcher, DrawScale.Factory(scaleX, scaleY, pivot)) } override fun anchoredSize( @@ -219,12 +226,12 @@ internal abstract class BaseTransitionBuilderImpl : BaseTransitionBuilder { anchorWidth: Boolean, anchorHeight: Boolean, ) { - addTransformation(AnchoredSize(matcher, anchor, anchorWidth, anchorHeight)) + addTransformation(matcher, AnchoredSize.Factory(anchor, anchorWidth, anchorHeight)) } - override fun transformation(transformation: CustomPropertyTransformation<*>) { + override fun transformation(matcher: ElementMatcher, transformation: Transformation.Factory) { check(range == null) { "Custom transformations can not be applied inside a range" } - addTransformation(transformation) + addTransformation(matcher, transformation) } } @@ -263,7 +270,10 @@ internal class TransitionBuilderImpl(override val transition: TransitionState.Tr "(${transition.toContent.debugName})" } - addTransformation(SharedElementTransformation(matcher, enabled, elevateInContent)) + addTransformation( + matcher, + SharedElementTransformation.Factory(matcher, enabled, elevateInContent), + ) } override fun timestampRange( @@ -294,6 +304,6 @@ internal open class OverscrollBuilderImpl : BaseTransitionBuilderImpl(), Overscr x: OverscrollScope.() -> Float, y: OverscrollScope.() -> Float, ) { - addTransformation(OverscrollTranslate(matcher, x, y)) + addTransformation(matcher, OverscrollTranslate.Factory(x, y)) } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt index 38b1aaa7558d..33f015fe49d9 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt @@ -401,7 +401,7 @@ sealed interface TransitionState { else -> null } ?: return true - return specForCurrentScene.transformationSpec.transformations.isNotEmpty() + return specForCurrentScene.transformationSpec.transformationMatchers.isNotEmpty() } internal open fun interruptionProgress(layoutImpl: SceneTransitionLayoutImpl): Float { diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt new file mode 100644 index 000000000000..bfb5ca733d90 --- /dev/null +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt @@ -0,0 +1,289 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.compose.animation.scene.reveal + +import androidx.compose.animation.core.AnimationVector1D +import androidx.compose.animation.core.DeferredTargetAnimation +import androidx.compose.animation.core.ExperimentalAnimatableApi +import androidx.compose.animation.core.FiniteAnimationSpec +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.VectorConverter +import androidx.compose.animation.core.spring +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp +import androidx.compose.ui.util.fastCoerceAtLeast +import androidx.compose.ui.util.fastCoerceAtMost +import com.android.compose.animation.scene.ContentKey +import com.android.compose.animation.scene.ElementKey +import com.android.compose.animation.scene.OverlayKey +import com.android.compose.animation.scene.SceneKey +import com.android.compose.animation.scene.TransitionBuilder +import com.android.compose.animation.scene.UserActionDistance +import com.android.compose.animation.scene.content.state.TransitionState +import com.android.compose.animation.scene.transformation.CustomPropertyTransformation +import com.android.compose.animation.scene.transformation.PropertyTransformation +import com.android.compose.animation.scene.transformation.PropertyTransformationScope +import kotlin.math.roundToInt +import kotlinx.coroutines.CoroutineScope + +interface ContainerRevealHaptics { + /** + * Called when the reveal threshold is crossed while the user was dragging on screen. + * + * Important: This callback is called during layout and its implementation should therefore be + * very fast or posted to a different thread. + * + * @param revealed whether we go from hidden to revealed, i.e. whether the container size is + * going to jump from a smaller size to a bigger size. + */ + fun onRevealThresholdCrossed(revealed: Boolean) +} + +/** Animate the reveal of [container] by animating its size. */ +fun TransitionBuilder.verticalContainerReveal( + container: ElementKey, + haptics: ContainerRevealHaptics, +) { + // Make the swipe distance be exactly the target height of the container. + // TODO(b/376438969): Make sure that this works correctly when the target size of the element + // is changing during the transition (e.g. a notification was added). At the moment, the user + // action distance is only called until it returns a value > 0f, which is then cached. + distance = UserActionDistance { fromContent, toContent, _ -> + val targetSizeInFromContent = container.targetSize(fromContent) + val targetSizeInToContent = container.targetSize(toContent) + if (targetSizeInFromContent != null && targetSizeInToContent != null) { + error( + "verticalContainerReveal should not be used with shared elements, but " + + "${container.debugName} is in both ${fromContent.debugName} and " + + toContent.debugName + ) + } + + (targetSizeInToContent?.height ?: targetSizeInFromContent?.height)?.toFloat() ?: 0f + } + + // TODO(b/376438969): Improve the motion of this gesture using Motion Mechanics. + + // The min distance to swipe before triggering the reveal spring. + val distanceThreshold = 80.dp + + // The minimum height of the container. + val minHeight = 10.dp + + // The amount removed from the container width at 0% progress. + val widthDelta = 140.dp + + // The ratio at which the distance is tracked before reaching the threshold, e.g. if the user + // drags 60dp then the height will be 60dp * 0.25f = 15dp. + val trackingRatio = 0.25f + + // The max progress starting from which the container should always be visible, even if we are + // animating the container out. This is used so that we don't immediately fade out the container + // when triggering a one-off animation that hides it. + val alphaProgressThreshold = 0.05f + + // The spring animating the size of the container. + val sizeSpec = spring<Float>(stiffness = 380f, dampingRatio = 0.9f) + + // The spring animating the alpha of the container. + val alphaSpec = spring<Float>(stiffness = 1200f, dampingRatio = 0.99f) + + // The spring animating the progress when releasing the finger. + swipeSpec = + spring( + stiffness = Spring.StiffnessMediumLow, + dampingRatio = Spring.DampingRatioNoBouncy, + visibilityThreshold = 0.5f, + ) + + // Size transformation. + transformation(container) { + VerticalContainerRevealSizeTransformation( + haptics, + distanceThreshold, + trackingRatio, + minHeight, + widthDelta, + sizeSpec, + ) + } + + // Alpha transformation. + transformation(container) { + ContainerRevealAlphaTransformation(alphaSpec, alphaProgressThreshold) + } +} + +@OptIn(ExperimentalAnimatableApi::class) +private class VerticalContainerRevealSizeTransformation( + private val haptics: ContainerRevealHaptics, + private val distanceThreshold: Dp, + private val trackingRatio: Float, + private val minHeight: Dp, + private val widthDelta: Dp, + private val spec: FiniteAnimationSpec<Float>, +) : CustomPropertyTransformation<IntSize> { + override val property = PropertyTransformation.Property.Size + + private val widthAnimation = DeferredTargetAnimation(Float.VectorConverter) + private val heightAnimation = DeferredTargetAnimation(Float.VectorConverter) + + private var previousHasReachedThreshold: Boolean? = null + + override fun PropertyTransformationScope.transform( + content: ContentKey, + element: ElementKey, + transition: TransitionState.Transition, + transitionScope: CoroutineScope, + ): IntSize { + // The distance to go to 100%. Note that we don't use + // TransitionState.HasOverscrollProperties.absoluteDistance because the transition will not + // implement HasOverscrollProperties if the transition is triggered and not gesture based. + val idleSize = checkNotNull(element.targetSize(content)) + val userActionDistance = idleSize.height + val progress = + when ((transition as? TransitionState.HasOverscrollProperties)?.bouncingContent) { + null -> transition.progressTo(content) + content -> 1f + else -> 0f + } + val distance = (progress * userActionDistance).fastCoerceAtLeast(0f) + val threshold = distanceThreshold.toPx() + + // Width. + val widthDelta = widthDelta.toPx() + val width = + (idleSize.width - widthDelta + + animateSize( + size = widthDelta, + distance = distance, + threshold = threshold, + transitionScope = transitionScope, + animation = widthAnimation, + )) + .roundToInt() + + // Height. + val minHeight = minHeight.toPx() + val height = + ( + // 1) The minimum size of the container. + minHeight + + + // 2) The animated size between the minimum size and the threshold. + animateSize( + size = threshold - minHeight, + distance = distance, + threshold = threshold, + transitionScope = transitionScope, + animation = heightAnimation, + ) + + + // 3) The remaining height after the threshold, tracking the finger. + (distance - threshold).fastCoerceAtLeast(0f)) + .roundToInt() + .fastCoerceAtMost(idleSize.height) + + // Haptics. + val hasReachedThreshold = distance >= threshold + if ( + previousHasReachedThreshold != null && + hasReachedThreshold != previousHasReachedThreshold && + transition.isUserInputOngoing + ) { + haptics.onRevealThresholdCrossed(revealed = hasReachedThreshold) + } + previousHasReachedThreshold = hasReachedThreshold + + return IntSize(width = width, height = height) + } + + /** + * Animate a size up to [size], so that it is equal to 0f when distance is 0f and equal to + * [size] when `distance >= threshold`, taking the [trackingRatio] into account. + */ + @OptIn(ExperimentalAnimatableApi::class) + private fun animateSize( + size: Float, + distance: Float, + threshold: Float, + transitionScope: CoroutineScope, + animation: DeferredTargetAnimation<Float, AnimationVector1D>, + ): Float { + val trackingSize = distance.fastCoerceAtMost(threshold) / threshold * size * trackingRatio + val springTarget = + if (distance >= threshold) { + size * (1f - trackingRatio) + } else { + 0f + } + val springSize = animation.updateTarget(springTarget, transitionScope, spec) + return trackingSize + springSize + } +} + +@OptIn(ExperimentalAnimatableApi::class) +private class ContainerRevealAlphaTransformation( + private val spec: FiniteAnimationSpec<Float>, + private val progressThreshold: Float, +) : CustomPropertyTransformation<Float> { + override val property = PropertyTransformation.Property.Alpha + private val alphaAnimation = DeferredTargetAnimation(Float.VectorConverter) + + override fun PropertyTransformationScope.transform( + content: ContentKey, + element: ElementKey, + transition: TransitionState.Transition, + transitionScope: CoroutineScope, + ): Float { + return alphaAnimation.updateTarget(targetAlpha(transition, content), transitionScope, spec) + } + + private fun targetAlpha(transition: TransitionState.Transition, content: ContentKey): Float { + if (transition.isUserInputOngoing) { + if (transition !is TransitionState.HasOverscrollProperties) { + error( + "Unsupported transition driven by user input but that does not have " + + "overscroll properties: $transition" + ) + } + + val bouncingContent = transition.bouncingContent + return if (bouncingContent != null) { + if (bouncingContent == content) 1f else 0f + } else { + if (transition.progressTo(content) > 0f) 1f else 0f + } + } + + // The transition was committed (the user released their finger), so the alpha depends on + // whether we are animating towards the content (showing the container) or away from it + // (hiding the container). + val isShowingContainer = + when (content) { + is SceneKey -> transition.currentScene == content + is OverlayKey -> transition.currentOverlays.contains(content) + } + + return if (isShowingContainer || transition.progressTo(content) >= progressThreshold) { + 1f + } else { + 0f + } + } +} diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt index 85bb5336d574..6575068201d8 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredSize.kt @@ -19,16 +19,17 @@ package com.android.compose.animation.scene.transformation import androidx.compose.ui.unit.IntSize import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey -import com.android.compose.animation.scene.ElementMatcher import com.android.compose.animation.scene.content.state.TransitionState /** Anchor the size of an element to the size of another element. */ -internal class AnchoredSize( - override val matcher: ElementMatcher, +internal class AnchoredSize +private constructor( private val anchor: ElementKey, private val anchorWidth: Boolean, private val anchorHeight: Boolean, -) : InterpolatedSizeTransformation { +) : InterpolatedPropertyTransformation<IntSize> { + override val property = PropertyTransformation.Property.Size + override fun PropertyTransformationScope.transform( content: ContentKey, element: ElementKey, @@ -59,4 +60,12 @@ internal class AnchoredSize( anchorSizeIn(transition.fromContent) } } + + class Factory( + private val anchor: ElementKey, + private val anchorWidth: Boolean, + private val anchorHeight: Boolean, + ) : Transformation.Factory { + override fun create(): Transformation = AnchoredSize(anchor, anchorWidth, anchorHeight) + } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt index 04cd68344252..890902b7ab67 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/AnchoredTranslate.kt @@ -19,14 +19,13 @@ package com.android.compose.animation.scene.transformation import androidx.compose.ui.geometry.Offset import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey -import com.android.compose.animation.scene.ElementMatcher import com.android.compose.animation.scene.content.state.TransitionState /** Anchor the translation of an element to another element. */ -internal class AnchoredTranslate( - override val matcher: ElementMatcher, - private val anchor: ElementKey, -) : InterpolatedOffsetTransformation { +internal class AnchoredTranslate private constructor(private val anchor: ElementKey) : + InterpolatedPropertyTransformation<Offset> { + override val property = PropertyTransformation.Property.Offset + override fun PropertyTransformationScope.transform( content: ContentKey, element: ElementKey, @@ -56,6 +55,10 @@ internal class AnchoredTranslate( Offset(idleValue.x + offset.x, idleValue.y + offset.y) } } + + class Factory(private val anchor: ElementKey) : Transformation.Factory { + override fun create(): Transformation = AnchoredTranslate(anchor) + } } internal fun throwMissingAnchorException( diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt index 45d6d4037c49..347f1c325058 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/DrawScale.kt @@ -19,7 +19,6 @@ package com.android.compose.animation.scene.transformation import androidx.compose.ui.geometry.Offset import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey -import com.android.compose.animation.scene.ElementMatcher import com.android.compose.animation.scene.Scale import com.android.compose.animation.scene.content.state.TransitionState @@ -27,12 +26,14 @@ import com.android.compose.animation.scene.content.state.TransitionState * Scales the draw size of an element. Note this will only scale the draw inside of an element, * therefore it won't impact layout of elements around it. */ -internal class DrawScale( - override val matcher: ElementMatcher, +internal class DrawScale +private constructor( private val scaleX: Float, private val scaleY: Float, - private val pivot: Offset = Offset.Unspecified, -) : InterpolatedScaleTransformation { + private val pivot: Offset, +) : InterpolatedPropertyTransformation<Scale> { + override val property = PropertyTransformation.Property.Scale + override fun PropertyTransformationScope.transform( content: ContentKey, element: ElementKey, @@ -41,4 +42,9 @@ internal class DrawScale( ): Scale { return Scale(scaleX, scaleY, pivot) } + + class Factory(private val scaleX: Float, private val scaleY: Float, private val pivot: Offset) : + Transformation.Factory { + override fun create(): Transformation = DrawScale(scaleX, scaleY, pivot) + } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt index 21d66d784e2d..f8e6dc09ce75 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/EdgeTranslate.kt @@ -20,15 +20,14 @@ import androidx.compose.ui.geometry.Offset import com.android.compose.animation.scene.ContentKey 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.content.state.TransitionState /** Translate an element from an edge of the layout. */ -internal class EdgeTranslate( - override val matcher: ElementMatcher, - private val edge: Edge, - private val startsOutsideLayoutBounds: Boolean = true, -) : InterpolatedOffsetTransformation { +internal class EdgeTranslate +private constructor(private val edge: Edge, private val startsOutsideLayoutBounds: Boolean) : + InterpolatedPropertyTransformation<Offset> { + override val property = PropertyTransformation.Property.Offset + override fun PropertyTransformationScope.transform( content: ContentKey, element: ElementKey, @@ -67,4 +66,9 @@ internal class EdgeTranslate( } } } + + class Factory(private val edge: Edge, private val startsOutsideLayoutBounds: Boolean) : + Transformation.Factory { + override fun create(): Transformation = EdgeTranslate(edge, startsOutsideLayoutBounds) + } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt index d942273ab9ab..d92419ef368d 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Fade.kt @@ -18,11 +18,12 @@ package com.android.compose.animation.scene.transformation import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey -import com.android.compose.animation.scene.ElementMatcher import com.android.compose.animation.scene.content.state.TransitionState /** Fade an element in or out. */ -internal class Fade(override val matcher: ElementMatcher) : InterpolatedAlphaTransformation { +internal object Fade : InterpolatedPropertyTransformation<Float> { + override val property = PropertyTransformation.Property.Alpha + override fun PropertyTransformationScope.transform( content: ContentKey, element: ElementKey, @@ -33,4 +34,8 @@ internal class Fade(override val matcher: ElementMatcher) : InterpolatedAlphaTra // fading out, which is `0` in both cases. return 0f } + + object Factory : Transformation.Factory { + override fun create(): Transformation = Fade + } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt index 5f3cdab3c572..5d31fd9ca196 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/ScaleSize.kt @@ -19,7 +19,6 @@ package com.android.compose.animation.scene.transformation import androidx.compose.ui.unit.IntSize import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey -import com.android.compose.animation.scene.ElementMatcher import com.android.compose.animation.scene.content.state.TransitionState import kotlin.math.roundToInt @@ -27,11 +26,10 @@ import kotlin.math.roundToInt * Scales the size of an element. Note that this makes the element resize every frame and will * therefore impact the layout of other elements. */ -internal class ScaleSize( - override val matcher: ElementMatcher, - private val width: Float = 1f, - private val height: Float = 1f, -) : InterpolatedSizeTransformation { +internal class ScaleSize private constructor(private val width: Float, private val height: Float) : + InterpolatedPropertyTransformation<IntSize> { + override val property = PropertyTransformation.Property.Size + override fun PropertyTransformationScope.transform( content: ContentKey, element: ElementKey, @@ -43,4 +41,9 @@ internal class ScaleSize( height = (idleValue.height * height).roundToInt(), ) } + + class Factory(private val width: Float = 1f, private val height: Float = 1f) : + Transformation.Factory { + override fun create(): Transformation = ScaleSize(width, height) + } } diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt index d5143d729f2e..e0b42189854a 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Transformation.kt @@ -35,26 +35,59 @@ import kotlinx.coroutines.CoroutineScope /** A transformation applied to one or more elements during a transition. */ sealed interface Transformation { - /** - * The matcher that should match the element(s) to which this transformation should be applied. - */ - val matcher: ElementMatcher + fun interface Factory { + fun create(): Transformation + } } -internal class SharedElementTransformation( - override val matcher: ElementMatcher, +// Important: SharedElementTransformation must be a data class because we check that we don't +// provide 2 different transformations for the same element in Element.kt +internal data class SharedElementTransformation( internal val enabled: Boolean, internal val elevateInContent: ContentKey?, -) : Transformation +) : Transformation { + class Factory( + internal val matcher: ElementMatcher, + internal val enabled: Boolean, + internal val elevateInContent: ContentKey?, + ) : Transformation.Factory { + override fun create(): Transformation { + return SharedElementTransformation(enabled, elevateInContent) + } + } +} + +/** + * A transformation that changes the value of an element [Property], like its [size][Property.Size] + * or [offset][Property.Offset]. + */ +sealed interface PropertyTransformation<T> : Transformation { + /** The property to which this transformation is applied. */ + val property: Property<T> + + sealed class Property<T> { + /** The size of an element. */ + data object Size : Property<IntSize>() + + /** The offset (position) of an element. */ + data object Offset : Property<androidx.compose.ui.geometry.Offset>() + + /** The alpha of an element. */ + data object Alpha : Property<Float>() -/** A transformation that changes the value of an element property, like its size or offset. */ -sealed interface PropertyTransformation<T> : Transformation + /** + * The drawing scale of an element. Animating the scale does not have any effect on the + * layout. + */ + data object Scale : Property<com.android.compose.animation.scene.Scale>() + } +} /** * A transformation to a target/transformed value that is automatically interpolated using the * transition progress and transformation range. */ -sealed interface InterpolatedPropertyTransformation<T> : PropertyTransformation<T> { +interface InterpolatedPropertyTransformation<T> : PropertyTransformation<T> { /** * Return the transformed value for the given property, i.e.: * - the value at progress = 0% for elements that are entering the layout (i.e. elements in the @@ -73,19 +106,7 @@ sealed interface InterpolatedPropertyTransformation<T> : PropertyTransformation< ): T } -/** An [InterpolatedPropertyTransformation] applied to the size of one or more elements. */ -interface InterpolatedSizeTransformation : InterpolatedPropertyTransformation<IntSize> - -/** An [InterpolatedPropertyTransformation] applied to the offset of one or more elements. */ -interface InterpolatedOffsetTransformation : InterpolatedPropertyTransformation<Offset> - -/** An [InterpolatedPropertyTransformation] applied to the alpha of one or more elements. */ -interface InterpolatedAlphaTransformation : InterpolatedPropertyTransformation<Float> - -/** An [InterpolatedPropertyTransformation] applied to the scale of one or more elements. */ -interface InterpolatedScaleTransformation : InterpolatedPropertyTransformation<Scale> - -sealed interface CustomPropertyTransformation<T> : PropertyTransformation<T> { +interface CustomPropertyTransformation<T> : PropertyTransformation<T> { /** * Return the value that the property should have in the current frame for the given [content] * and [element]. @@ -105,25 +126,20 @@ sealed interface CustomPropertyTransformation<T> : PropertyTransformation<T> { ): T } -/** A [CustomPropertyTransformation] applied to the size of one or more elements. */ -interface CustomSizeTransformation : CustomPropertyTransformation<IntSize> - -/** A [CustomPropertyTransformation] applied to the offset of one or more elements. */ -interface CustomOffsetTransformation : CustomPropertyTransformation<Offset> - -/** A [CustomPropertyTransformation] applied to the alpha of one or more elements. */ -interface CustomAlphaTransformation : CustomPropertyTransformation<Float> - -/** A [CustomPropertyTransformation] applied to the scale of one or more elements. */ -interface CustomScaleTransformation : CustomPropertyTransformation<Scale> - interface PropertyTransformationScope : Density, ElementStateScope { /** The current [direction][LayoutDirection] of the layout. */ val layoutDirection: LayoutDirection } +/** Defines the transformation-type to be applied to all elements matching [matcher]. */ +internal class TransformationMatcher( + val matcher: ElementMatcher, + val factory: Transformation.Factory, + val range: TransformationRange?, +) + /** A pair consisting of a [transformation] and optional [range]. */ -class TransformationWithRange<out T : Transformation>( +internal data class TransformationWithRange<out T : Transformation>( val transformation: T, val range: TransformationRange?, ) { @@ -135,7 +151,7 @@ class TransformationWithRange<out T : Transformation>( } /** The progress-based range of a [PropertyTransformation]. */ -data class TransformationRange(val start: Float, val end: Float, val easing: Easing) { +internal data class TransformationRange(val start: Float, val end: Float, val easing: Easing) { constructor( start: Float? = null, end: Float? = null, diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt index d756c86f680c..2f4d5bff8b41 100644 --- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt +++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/transformation/Translate.kt @@ -19,18 +19,15 @@ package com.android.compose.animation.scene.transformation import androidx.compose.ui.geometry.Offset import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey -import com.android.compose.animation.scene.ElementMatcher import com.android.compose.animation.scene.OverscrollScope import com.android.compose.animation.scene.content.state.TransitionState -internal class Translate( - override val matcher: ElementMatcher, - private val x: Dp = 0.dp, - private val y: Dp = 0.dp, -) : InterpolatedOffsetTransformation { +internal class Translate private constructor(private val x: Dp, private val y: Dp) : + InterpolatedPropertyTransformation<Offset> { + override val property = PropertyTransformation.Property.Offset + override fun PropertyTransformationScope.transform( content: ContentKey, element: ElementKey, @@ -39,13 +36,19 @@ internal class Translate( ): Offset { return Offset(idleValue.x + x.toPx(), idleValue.y + y.toPx()) } + + class Factory(private val x: Dp, private val y: Dp) : Transformation.Factory { + override fun create(): Transformation = Translate(x, y) + } } -internal class OverscrollTranslate( - override val matcher: ElementMatcher, - val x: OverscrollScope.() -> Float = { 0f }, - val y: OverscrollScope.() -> Float = { 0f }, -) : InterpolatedOffsetTransformation { +internal class OverscrollTranslate +private constructor( + private val x: OverscrollScope.() -> Float, + private val y: OverscrollScope.() -> Float, +) : InterpolatedPropertyTransformation<Offset> { + override val property = PropertyTransformation.Property.Offset + private val cachedOverscrollScope = CachedOverscrollScope() override fun PropertyTransformationScope.transform( @@ -63,6 +66,13 @@ internal class OverscrollTranslate( return Offset(x = value.x + overscrollScope.x(), y = value.y + overscrollScope.y()) } + + class Factory( + private val x: OverscrollScope.() -> Float, + private val y: OverscrollScope.() -> Float, + ) : Transformation.Factory { + override fun create(): Transformation = OverscrollTranslate(x, y) + } } /** diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt index 61e9bb0db0f7..10057b280d28 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/DraggableHandlerTest.kt @@ -644,7 +644,7 @@ class DraggableHandlerTest { mutableUserActionsA = emptyMap() mutableUserActionsB = emptyMap() - // start accelaratedScroll and scroll over to B -> null + // start acceleratedScroll and scroll over to B -> null val dragController2 = onDragStartedImmediately() dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = 0f) dragController2.onDragDelta(pixels = up(fractionOfScreen = 0.5f), expectedConsumed = 0f) @@ -1530,7 +1530,7 @@ class DraggableHandlerTest { fun interceptingTransitionKeepsDistance() = runGestureTest { var swipeDistance = 75f layoutState.transitions = transitions { - from(SceneA, to = SceneB) { distance = UserActionDistance { _, _ -> swipeDistance } } + from(SceneA, to = SceneB) { distance = UserActionDistance { _, _, _ -> swipeDistance } } } // Start transition. diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt index 09b59394724d..b4c8ad7c3327 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/MovableElementTest.kt @@ -35,6 +35,7 @@ import androidx.compose.ui.test.assertIsDisplayed import androidx.compose.ui.test.assertIsNotDisplayed import androidx.compose.ui.test.assertPositionInRootIsEqualTo import androidx.compose.ui.test.hasParent +import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.createComposeRule import androidx.compose.ui.test.onAllNodesWithText @@ -404,4 +405,40 @@ class MovableElementTest { rule.waitForIdle() rule.onNodeWithTag(fooParentInOverlayTag).assertSizeIsEqualTo(fooSize) } + + @Test + fun movableElementInOverlayShouldBeComposed() { + val fooKey = MovableElementKey("foo", contents = setOf(OverlayA)) + val fooContentTag = "fooContentTag" + + @Composable + fun ContentScope.MovableFoo(modifier: Modifier = Modifier) { + MovableElement(fooKey, modifier) { + content { Box(Modifier.testTag(fooContentTag).size(100.dp)) } + } + } + + val state = + rule.runOnUiThread { + MutableSceneTransitionLayoutState( + initialScene = SceneA, + initialOverlays = setOf(OverlayA), + ) + } + + val scope = + rule.setContentAndCreateMainScope { + SceneTransitionLayout(state) { + scene(SceneA) { Box(Modifier.fillMaxSize()) } + overlay(OverlayA) { MovableFoo() } + overlay(OverlayB) { Box(Modifier.size(50.dp)) } + } + } + + rule.onNode(hasTestTag(fooContentTag)).assertIsDisplayed().assertSizeIsEqualTo(100.dp) + + // Show overlay B. This shouldn't have any impact on Foo that should still be composed in A. + scope.launch { state.startTransition(transition(SceneA, OverlayB)) } + rule.onNode(hasTestTag(fooContentTag)).assertIsDisplayed().assertSizeIsEqualTo(100.dp) + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt index 57ad81ebf7f0..79ca891babd1 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutStateTest.kt @@ -153,7 +153,7 @@ class SceneTransitionLayoutStateTest { // Default transition from A to B. assertThat(state.setTargetScene(SceneB, animationScope = this)).isNotNull() - assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1) + assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(1) // Go back to A. state.setTargetScene(SceneA, animationScope = this) @@ -166,7 +166,7 @@ class SceneTransitionLayoutStateTest { state.setTargetScene(SceneB, animationScope = this, transitionKey = transitionkey) ) .isNotNull() - assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2) + assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(2) } @Test @@ -686,4 +686,30 @@ class SceneTransitionLayoutStateTest { assertThat(state.transitionState).isIdle() assertThat(job.isCancelled).isTrue() } + + @Test + fun badTransitionSpecThrowsMeaningfulMessageWhenStartingTransition() { + val state = + MutableSceneTransitionLayoutState( + SceneA, + transitions { + // This transition definition is bad because they both match when transitioning + // from A to B. + from(SceneA) {} + to(SceneB) {} + }, + ) + + val exception = + assertThrows(IllegalStateException::class.java) { + runBlocking { state.startTransition(transition(from = SceneA, to = SceneB)) } + } + + assertThat(exception) + .hasMessageThat() + .isEqualTo( + "Found multiple transition specs for transition SceneKey(debugName=SceneA) => " + + "SceneKey(debugName=SceneB)" + ) + } } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt index 97a96a4333cb..b3a3261122a8 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt @@ -55,7 +55,6 @@ import androidx.compose.ui.test.swipeRight import androidx.compose.ui.test.swipeUp import androidx.compose.ui.test.swipeWithVelocity import androidx.compose.ui.unit.Density -import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -672,12 +671,12 @@ class SwipeToSceneTest { } assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue() - assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(1) + assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(1) // Move the pointer up to swipe to scene B using the new transition. rule.onRoot().performTouchInput { moveBy(Offset(0f, -1.dp.toPx()), delayMillis = 1_000) } assertThat(state.isTransitioning(from = SceneA, to = SceneB)).isTrue() - assertThat(state.currentTransition?.transformationSpec?.transformations).hasSize(2) + assertThat(state.currentTransition?.transformationSpec?.transformationMatchers).hasSize(2) } @Test @@ -685,7 +684,8 @@ class SwipeToSceneTest { val swipeDistance = object : UserActionDistance { override fun UserActionDistanceScope.absoluteDistance( - fromSceneSize: IntSize, + fromContent: ContentKey, + toContent: ContentKey, orientation: Orientation, ): Float { // Foo is going to have a vertical offset of 50dp. Let's make the swipe distance diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt index 1f9ba9ee9372..70f2ff80f9d7 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/TransitionDslTest.kt @@ -28,11 +28,12 @@ import com.android.compose.animation.scene.TestScenes.SceneA import com.android.compose.animation.scene.TestScenes.SceneB import com.android.compose.animation.scene.TestScenes.SceneC import com.android.compose.animation.scene.content.state.TransitionState -import com.android.compose.animation.scene.transformation.CustomSizeTransformation +import com.android.compose.animation.scene.transformation.CustomPropertyTransformation import com.android.compose.animation.scene.transformation.OverscrollTranslate +import com.android.compose.animation.scene.transformation.PropertyTransformation import com.android.compose.animation.scene.transformation.PropertyTransformationScope +import com.android.compose.animation.scene.transformation.TransformationMatcher import com.android.compose.animation.scene.transformation.TransformationRange -import com.android.compose.animation.scene.transformation.TransformationWithRange import com.android.compose.test.transition import com.google.common.truth.Correspondence import com.google.common.truth.Truth.assertThat @@ -103,7 +104,7 @@ class TransitionDslTest { val transitions = transitions { from(SceneA, to = SceneB) { fade(TestElements.Foo) } } val transformations = - transitions.transitionSpecs.single().transformationSpec(aToB()).transformations + transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers assertThat(transformations.size).isEqualTo(1) assertThat(transformations.single().range).isEqualTo(null) } @@ -126,7 +127,7 @@ class TransitionDslTest { } val transformations = - transitions.transitionSpecs.single().transformationSpec(aToB()).transformations + transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) .containsExactly( @@ -157,7 +158,7 @@ class TransitionDslTest { } val transformations = - transitions.transitionSpecs.single().transformationSpec(aToB()).transformations + transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) .containsExactly( @@ -185,7 +186,7 @@ class TransitionDslTest { } val transformations = - transitions.transitionSpecs.single().transformationSpec(aToB()).transformations + transitions.transitionSpecs.single().transformationSpec(aToB()).transformationMatchers assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) .containsExactly( @@ -215,7 +216,7 @@ class TransitionDslTest { // to B we defined. val transitionSpec = transitions.transitionSpec(from = SceneB, to = SceneA, key = null) - val transformations = transitionSpec.transformationSpec(aToB()).transformations + val transformations = transitionSpec.transformationSpec(aToB()).transformationMatchers assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) @@ -225,7 +226,7 @@ class TransitionDslTest { ) val previewTransformations = - transitionSpec.previewTransformationSpec(aToB())?.transformations + transitionSpec.previewTransformationSpec(aToB())?.transformationMatchers assertThat(previewTransformations) .comparingElementsUsing(TRANSFORMATION_RANGE) @@ -255,7 +256,7 @@ class TransitionDslTest { key = TransitionKey.PredictiveBack, ) - val transformations = transitionSpec.transformationSpec(aToB()).transformations + val transformations = transitionSpec.transformationSpec(aToB()).transformationMatchers assertThat(transformations) .comparingElementsUsing(TRANSFORMATION_RANGE) @@ -265,7 +266,7 @@ class TransitionDslTest { ) val previewTransformations = - transitionSpec.previewTransformationSpec(aToB())?.transformations + transitionSpec.previewTransformationSpec(aToB())?.transformationMatchers assertThat(previewTransformations) .comparingElementsUsing(TRANSFORMATION_RANGE) @@ -316,7 +317,7 @@ class TransitionDslTest { val overscrollSpec = transitions.overscrollSpecs.single() val transformation = - overscrollSpec.transformationSpec.transformations.single().transformation + overscrollSpec.transformationSpec.transformationMatchers.single().factory.create() assertThat(transformation).isInstanceOf(OverscrollTranslate::class.java) } @@ -324,7 +325,7 @@ class TransitionDslTest { fun overscrollSpec_for_overscrollDisabled() { val transitions = transitions { overscrollDisabled(SceneA, Orientation.Vertical) } val overscrollSpec = transitions.overscrollSpecs.single() - assertThat(overscrollSpec.transformationSpec.transformations).isEmpty() + assertThat(overscrollSpec.transformationSpec.transformationMatchers).isEmpty() } @Test @@ -353,9 +354,9 @@ class TransitionDslTest { val transitions = transitions { from(SceneA, to = SceneB) { fractionRange { - transformation( - object : CustomSizeTransformation { - override val matcher: ElementMatcher = TestElements.Foo + transformation(TestElements.Foo) { + object : CustomPropertyTransformation<IntSize> { + override val property = PropertyTransformation.Property.Size override fun PropertyTransformationScope.transform( content: ContentKey, @@ -364,7 +365,7 @@ class TransitionDslTest { transitionScope: CoroutineScope, ): IntSize = IntSize.Zero } - ) + } } } } @@ -377,7 +378,7 @@ class TransitionDslTest { companion object { private val TRANSFORMATION_RANGE = - Correspondence.transforming<TransformationWithRange<*>, TransformationRange?>( + Correspondence.transforming<TransformationMatcher, TransformationRange?>( { it?.range }, "has range equal to", ) diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt index 313379f4c74b..0adb4809dd2d 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/subjects/TransitionStateSubject.kt @@ -157,7 +157,7 @@ abstract class BaseTransitionSubject<T : TransitionState.Transition>( check("isUserInputOngoing").that(actual.isUserInputOngoing).isEqualTo(isUserInputOngoing) } - fun hasOverscrollSpec(): OverscrollSpec { + internal fun hasOverscrollSpec(): OverscrollSpec { check("currentOverscrollSpec").that(actual.currentOverscrollSpec).isNotNull() return actual.currentOverscrollSpec!! } diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt index 487b0992c3e5..444ec4ead561 100644 --- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt +++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/CustomTransformationTest.kt @@ -30,7 +30,6 @@ import androidx.compose.ui.unit.dp import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey -import com.android.compose.animation.scene.ElementMatcher import com.android.compose.animation.scene.TestElements import com.android.compose.animation.scene.content.state.TransitionState import com.android.compose.animation.scene.testTransition @@ -47,8 +46,9 @@ class CustomTransformationTest { @Test fun customSize() { /** A size transformation that adds [add] to the size of the transformed element(s). */ - class AddSizeTransformation(override val matcher: ElementMatcher, private val add: Dp) : - CustomSizeTransformation { + class AddSizeTransformation(private val add: Dp) : CustomPropertyTransformation<IntSize> { + override val property = PropertyTransformation.Property.Size + override fun PropertyTransformationScope.transform( content: ContentKey, element: ElementKey, @@ -69,7 +69,7 @@ class CustomTransformationTest { spec = tween(16 * 4, easing = LinearEasing) // Add 80dp to the width and height of Foo. - transformation(AddSizeTransformation(TestElements.Foo, 80.dp)) + transformation(TestElements.Foo) { AddSizeTransformation(80.dp) } }, ) { before { onElement(TestElements.Foo).assertSizeIsEqualTo(40.dp, 20.dp) } @@ -84,8 +84,9 @@ class CustomTransformationTest { @Test fun customOffset() { /** An offset transformation that adds [add] to the offset of the transformed element(s). */ - class AddOffsetTransformation(override val matcher: ElementMatcher, private val add: Dp) : - CustomOffsetTransformation { + class AddOffsetTransformation(private val add: Dp) : CustomPropertyTransformation<Offset> { + override val property = PropertyTransformation.Property.Offset + override fun PropertyTransformationScope.transform( content: ContentKey, element: ElementKey, @@ -106,7 +107,7 @@ class CustomTransformationTest { spec = tween(16 * 4, easing = LinearEasing) // Add 80dp to the offset of Foo. - transformation(AddOffsetTransformation(TestElements.Foo, 80.dp)) + transformation(TestElements.Foo) { AddOffsetTransformation(80.dp) } }, ) { before { onElement(TestElements.Foo).assertPositionInRootIsEqualTo(0.dp, 0.dp) } diff --git a/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml index 651e401681c6..18073adf9e7a 100644 --- a/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml +++ b/packages/SystemUI/customization/res/values-sw600dp-land/dimens.xml @@ -16,4 +16,5 @@ <resources> <dimen name="keyguard_smartspace_top_offset">0dp</dimen> + <dimen name="status_view_margin_horizontal">8dp</dimen> </resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sw600dp/dimens.xml b/packages/SystemUI/customization/res/values-sw600dp/dimens.xml index 10e630d44488..37cd590b979e 100644 --- a/packages/SystemUI/customization/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/customization/res/values-sw600dp/dimens.xml @@ -17,4 +17,5 @@ <resources> <!-- For portrait direction in unfold foldable device, we don't need keyguard_smartspace_top_offset--> <dimen name="keyguard_smartspace_top_offset">0dp</dimen> + <dimen name="status_view_margin_horizontal">62dp</dimen> </resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/customization/res/values-sw720dp-land/dimens.xml new file mode 100644 index 000000000000..c1cf42c4b0f0 --- /dev/null +++ b/packages/SystemUI/customization/res/values-sw720dp-land/dimens.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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. + --> + +<resources> + <dimen name="status_view_margin_horizontal">24dp</dimen> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/customization/res/values-sw720dp-port/dimens.xml new file mode 100644 index 000000000000..54dbeaa1a3dd --- /dev/null +++ b/packages/SystemUI/customization/res/values-sw720dp-port/dimens.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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. + --> + +<resources> + <dimen name="status_view_margin_horizontal">124dp</dimen> +</resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/res/values/dimens.xml b/packages/SystemUI/customization/res/values/dimens.xml index 7feea6e5e8dd..041ae62670e5 100644 --- a/packages/SystemUI/customization/res/values/dimens.xml +++ b/packages/SystemUI/customization/res/values/dimens.xml @@ -39,4 +39,5 @@ <!--Dimens used in both lockscreen preview and smartspace --> <dimen name="date_weather_view_height">24dp</dimen> <dimen name="enhanced_smartspace_height">104dp</dimen> + <dimen name="status_view_margin_horizontal">0dp</dimen> </resources>
\ No newline at end of file diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AssetLoader.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AssetLoader.kt deleted file mode 100644 index 2a2d33308d12..000000000000 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AssetLoader.kt +++ /dev/null @@ -1,252 +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.shared.clocks - -import android.content.Context -import android.content.res.Resources -import android.graphics.Typeface -import android.graphics.drawable.Drawable -import android.util.TypedValue -import com.android.internal.policy.SystemBarUtils -import com.android.systemui.log.core.Logger -import com.android.systemui.log.core.MessageBuffer -import com.android.systemui.monet.Style as MonetStyle -import java.io.IOException - -class AssetLoader -private constructor( - private val pluginCtx: Context, - private val sysuiCtx: Context, - private val baseDir: String, - var seedColor: Int?, - var overrideChroma: Float?, - val typefaceCache: TypefaceCache, - messageBuffer: MessageBuffer, -) { - val logger = Logger(messageBuffer, TAG) - private val resources = - listOf( - Pair(pluginCtx.resources, pluginCtx.packageName), - Pair(sysuiCtx.resources, sysuiCtx.packageName), - ) - - constructor( - pluginCtx: Context, - sysuiCtx: Context, - baseDir: String, - messageBuffer: MessageBuffer, - ) : this( - pluginCtx, - sysuiCtx, - baseDir, - seedColor = null, - overrideChroma = null, - typefaceCache = - TypefaceCache(messageBuffer) { - // TODO(b/364680873): Move constant to config_clockFontFamily when shipping - return@TypefaceCache Typeface.create("google-sans-flex-clock", Typeface.NORMAL) - }, - messageBuffer = messageBuffer, - ) - - fun listAssets(path: String): List<String> { - return pluginCtx.resources.assets.list("$baseDir$path")?.toList() ?: emptyList() - } - - fun tryReadString(resStr: String): String? = tryRead(resStr, ::readString) - - fun readString(resStr: String): String { - val resPair = resolveResourceId(resStr) - if (resPair == null) { - throw IOException("Failed to parse string: $resStr") - } - - val (res, id) = resPair - return res.getString(id) - } - - fun readFontAsset(resStr: String): Typeface = typefaceCache.getTypeface(resStr) - - fun tryReadTextAsset(path: String?): String? = tryRead(path, ::readTextAsset) - - fun readTextAsset(path: String): String { - return pluginCtx.resources.assets.open("$baseDir$path").use { stream -> - val buffer = ByteArray(stream.available()) - stream.read(buffer) - String(buffer) - } - } - - fun tryReadDrawableAsset(path: String?): Drawable? = tryRead(path, ::readDrawableAsset) - - fun readDrawableAsset(path: String): Drawable { - var result: Drawable? - - if (path.startsWith("@")) { - val pair = resolveResourceId(path) - if (pair == null) { - throw IOException("Failed to parse $path to an id") - } - val (res, id) = pair - result = res.getDrawable(id) - } else if (path.endsWith("xml")) { - // TODO(b/248609434): Support xml files in assets - throw IOException("Cannot load xml files from assets") - } else { - // Attempt to load as if it's a bitmap and directly loadable - result = - pluginCtx.resources.assets.open("$baseDir$path").use { stream -> - Drawable.createFromResourceStream( - pluginCtx.resources, - TypedValue(), - stream, - null, - ) - } - } - - return result ?: throw IOException("Failed to load: $baseDir$path") - } - - fun parseResourceId(resStr: String): Triple<String?, String, String> { - if (!resStr.startsWith("@")) { - throw IOException("Invalid resource id: $resStr; Must start with '@'") - } - - // Parse out resource string - val parts = resStr.drop(1).split('/', ':') - return when (parts.size) { - 2 -> Triple(null, parts[0], parts[1]) - 3 -> Triple(parts[0], parts[1], parts[2]) - else -> throw IOException("Failed to parse resource string: $resStr") - } - } - - fun resolveResourceId(resStr: String): Pair<Resources, Int>? { - val (packageName, category, name) = parseResourceId(resStr) - return resolveResourceId(packageName, category, name) - } - - fun resolveResourceId( - packageName: String?, - category: String, - name: String, - ): Pair<Resources, Int>? { - for ((res, ctxPkgName) in resources) { - val result = res.getIdentifier(name, category, packageName ?: ctxPkgName) - if (result != 0) { - return Pair(res, result) - } - } - return null - } - - private fun <TArg : Any, TRes : Any> tryRead(arg: TArg?, fn: (TArg) -> TRes): TRes? { - try { - if (arg == null) { - return null - } - return fn(arg) - } catch (ex: IOException) { - logger.w("Failed to read $arg", ex) - return null - } - } - - fun assetExists(path: String): Boolean { - try { - if (path.startsWith("@")) { - val pair = resolveResourceId(path) - return pair != null - } else { - val stream = pluginCtx.resources.assets.open("$baseDir$path") - if (stream == null) { - return false - } - - stream.close() - return true - } - } catch (ex: IOException) { - return false - } - } - - fun copy(messageBuffer: MessageBuffer? = null): AssetLoader = - AssetLoader( - pluginCtx, - sysuiCtx, - baseDir, - seedColor, - overrideChroma, - typefaceCache, - messageBuffer ?: logger.buffer, - ) - - fun setSeedColor(seedColor: Int?, style: MonetStyle?) { - this.seedColor = seedColor - } - - fun getClockPaddingStart(): Int { - val result = resolveResourceId(null, "dimen", "clock_padding_start") - if (result != null) { - val (res, id) = result - return res.getDimensionPixelSize(id) - } - return -1 - } - - fun getStatusBarHeight(): Int { - val display = pluginCtx.getDisplayNoVerify() - if (display != null) { - return SystemBarUtils.getStatusBarHeight(pluginCtx.resources, display.cutout) - } - - logger.w("No display available; falling back to android.R.dimen.status_bar_height") - val statusBarHeight = resolveResourceId("android", "dimen", "status_bar_height") - if (statusBarHeight != null) { - val (res, resId) = statusBarHeight - return res.getDimensionPixelSize(resId) - } - - throw Exception("Could not fetch StatusBarHeight") - } - - fun getResourcesId(name: String): Int = getResource("id", name) { _, id -> id } - - fun getDimen(name: String): Int = getResource("dimen", name, Resources::getDimensionPixelSize) - - fun getString(name: String): String = getResource("string", name, Resources::getString) - - private fun <T> getResource( - category: String, - name: String, - getter: (res: Resources, id: Int) -> T, - ): T { - val result = resolveResourceId(null, category, name) - if (result != null) { - val (res, id) = result - if (id == -1) throw Exception("Cannot find id of $id from $TAG") - return getter(res, id) - } - throw Exception("Cannot find id of $name from $TAG") - } - - companion object { - private val TAG = AssetLoader::class.simpleName!! - } -} diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt index 4ed8fd8f631d..d0a32dcf9865 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/ComposedDigitalLayerController.kt @@ -16,12 +16,9 @@ package com.android.systemui.shared.clocks -import android.content.Context -import android.content.res.Resources import android.graphics.Rect import androidx.annotation.VisibleForTesting import com.android.systemui.log.core.Logger -import com.android.systemui.log.core.MessageBuffer import com.android.systemui.plugins.clocks.AlarmData import com.android.systemui.plugins.clocks.ClockAnimations import com.android.systemui.plugins.clocks.ClockEvents @@ -37,31 +34,22 @@ import java.util.Locale import java.util.TimeZone class ComposedDigitalLayerController( - private val ctx: Context, - private val resources: Resources, - private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources + private val clockCtx: ClockContext, private val layer: ComposedDigitalHandLayer, - messageBuffer: MessageBuffer, ) : SimpleClockLayerController { - private val logger = Logger(messageBuffer, ComposedDigitalLayerController::class.simpleName!!) + private val logger = + Logger(clockCtx.messageBuffer, ComposedDigitalLayerController::class.simpleName!!) val layerControllers = mutableListOf<SimpleClockLayerController>() val dozeState = DefaultClockController.AnimationState(1F) - override val view = FlexClockView(ctx, assets, messageBuffer) + override val view = FlexClockView(clockCtx) init { layer.digitalLayers.forEach { - val childView = SimpleDigitalClockTextView(ctx, messageBuffer) + val childView = SimpleDigitalClockTextView(clockCtx) val controller = - SimpleDigitalHandLayerController( - ctx, - resources, - assets, - it as DigitalHandLayer, - childView, - messageBuffer, - ) + SimpleDigitalHandLayerController(clockCtx, it as DigitalHandLayer, childView) view.addView(childView) layerControllers.add(controller) @@ -156,8 +144,9 @@ class ComposedDigitalLayerController( val color = when { theme.seedColor != null -> theme.seedColor!! - theme.isDarkTheme -> resources.getColor(android.R.color.system_accent1_100) - else -> resources.getColor(android.R.color.system_accent2_600) + theme.isDarkTheme -> + clockCtx.resources.getColor(android.R.color.system_accent1_100) + else -> clockCtx.resources.getColor(android.R.color.system_accent2_600) } view.updateColor(color) diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt index be4ebdfcb992..9bb92bc13416 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockProvider.kt @@ -15,10 +15,10 @@ package com.android.systemui.shared.clocks import android.content.Context import android.content.res.Resources +import android.graphics.Typeface import android.view.LayoutInflater import com.android.systemui.customization.R -import com.android.systemui.log.core.LogLevel -import com.android.systemui.log.core.LogcatOnlyMessageBuffer +import com.android.systemui.log.core.MessageBuffer import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockFontAxis import com.android.systemui.plugins.clocks.ClockFontAxisSetting @@ -33,6 +33,15 @@ import com.android.systemui.shared.clocks.view.VerticalAlignment private val TAG = DefaultClockProvider::class.simpleName const val DEFAULT_CLOCK_ID = "DEFAULT" +data class ClockContext( + val context: Context, + val resources: Resources, + val settings: ClockSettings, + val typefaceCache: TypefaceCache, + val messageBuffers: ClockMessageBuffers, + val messageBuffer: MessageBuffer, +) + /** Provides the default system clock */ class DefaultClockProvider( val ctx: Context, @@ -55,18 +64,20 @@ class DefaultClockProvider( } return if (isClockReactiveVariantsEnabled) { - val buffer = - messageBuffers?.infraMessageBuffer ?: LogcatOnlyMessageBuffer(LogLevel.INFO) - val assets = AssetLoader(ctx, ctx, "clocks/", buffer) - assets.setSeedColor(settings.seedColor, null) + val buffers = messageBuffers ?: ClockMessageBuffers(LogUtil.DEFAULT_MESSAGE_BUFFER) val fontAxes = ClockFontAxis.merge(FlexClockController.FONT_AXES, settings.axes) + val clockSettings = settings.copy(axes = fontAxes.map { it.toSetting() }) + val typefaceCache = TypefaceCache(buffers.infraMessageBuffer) { FLEX_TYPEFACE } FlexClockController( - ctx, - resources, - settings.copy(axes = fontAxes.map { it.toSetting() }), - assets, + ClockContext( + ctx, + resources, + clockSettings, + typefaceCache, + buffers, + buffers.infraMessageBuffer, + ), FLEX_DESIGN, - messageBuffers, ) } else { DefaultClockController( @@ -116,6 +127,11 @@ class DefaultClockProvider( ClockFontAxisSetting("slnt", 0f), ) + val FLEX_TYPEFACE by lazy { + // TODO(b/364680873): Move constant to config_clockFontFamily when shipping + Typeface.create("google-sans-flex-clock", Typeface.NORMAL) + } + val FLEX_DESIGN = run { val largeLayer = listOf( @@ -139,7 +155,7 @@ class DefaultClockProvider( alignment = DigitalAlignment( HorizontalAlignment.CENTER, - VerticalAlignment.CENTER, + VerticalAlignment.BASELINE, ), dateTimeFormat = "hh", ), @@ -158,7 +174,7 @@ class DefaultClockProvider( alignment = DigitalAlignment( HorizontalAlignment.CENTER, - VerticalAlignment.CENTER, + VerticalAlignment.BASELINE, ), dateTimeFormat = "hh", ), @@ -177,7 +193,7 @@ class DefaultClockProvider( alignment = DigitalAlignment( HorizontalAlignment.CENTER, - VerticalAlignment.CENTER, + VerticalAlignment.BASELINE, ), dateTimeFormat = "mm", ), @@ -196,7 +212,7 @@ class DefaultClockProvider( alignment = DigitalAlignment( HorizontalAlignment.CENTER, - VerticalAlignment.CENTER, + VerticalAlignment.BASELINE, ), dateTimeFormat = "mm", ), diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt index 6c627e27a19b..c7a3f63e92e7 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt @@ -16,8 +16,6 @@ package com.android.systemui.shared.clocks -import android.content.Context -import android.content.res.Resources import com.android.systemui.customization.R import com.android.systemui.plugins.clocks.AlarmData import com.android.systemui.plugins.clocks.AxisType @@ -26,8 +24,6 @@ import com.android.systemui.plugins.clocks.ClockController import com.android.systemui.plugins.clocks.ClockEvents import com.android.systemui.plugins.clocks.ClockFontAxis import com.android.systemui.plugins.clocks.ClockFontAxisSetting -import com.android.systemui.plugins.clocks.ClockMessageBuffers -import com.android.systemui.plugins.clocks.ClockSettings import com.android.systemui.plugins.clocks.ThemeConfig import com.android.systemui.plugins.clocks.WeatherData import com.android.systemui.plugins.clocks.ZenData @@ -38,42 +34,28 @@ import java.util.TimeZone /** Controller for the default flex clock */ class FlexClockController( - private val ctx: Context, - private val resources: Resources, - private val settings: ClockSettings, - private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources + private val clockCtx: ClockContext, val design: ClockDesign, // TODO(b/364680879): Remove when done inlining - val messageBuffers: ClockMessageBuffers?, ) : ClockController { - override val smallClock = run { - val buffer = messageBuffers?.smallClockMessageBuffer ?: LogUtil.DEFAULT_MESSAGE_BUFFER + override val smallClock = FlexClockFaceController( - ctx, - resources, - assets.copy(messageBuffer = buffer), + clockCtx.copy(messageBuffer = clockCtx.messageBuffers.smallClockMessageBuffer), design.small ?: design.large!!, - false, - buffer, + isLargeClock = false, ) - } - override val largeClock = run { - val buffer = messageBuffers?.largeClockMessageBuffer ?: LogUtil.DEFAULT_MESSAGE_BUFFER + override val largeClock = FlexClockFaceController( - ctx, - resources, - assets.copy(messageBuffer = buffer), + clockCtx.copy(messageBuffer = clockCtx.messageBuffers.largeClockMessageBuffer), design.large ?: design.small!!, - true, - buffer, + isLargeClock = true, ) - } override val config: ClockConfig by lazy { ClockConfig( DEFAULT_CLOCK_ID, - resources.getString(R.string.clock_default_name), - resources.getString(R.string.clock_default_description), + clockCtx.resources.getString(R.string.clock_default_name), + clockCtx.resources.getString(R.string.clock_default_description), isReactiveToTone = true, ) } @@ -125,8 +107,8 @@ class FlexClockController( } override fun initialize(isDarkTheme: Boolean, dozeFraction: Float, foldFraction: Float) { - val theme = ThemeConfig(isDarkTheme, assets.seedColor) - events.onFontAxesChanged(settings.axes) + val theme = ThemeConfig(isDarkTheme, clockCtx.settings.seedColor) + events.onFontAxesChanged(clockCtx.settings.axes) smallClock.run { events.onThemeChanged(theme) diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt index ee21ea6ee126..a8890e6aa934 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockFaceController.kt @@ -16,15 +16,12 @@ package com.android.systemui.shared.clocks -import android.content.Context -import android.content.res.Resources import android.graphics.Rect import android.view.Gravity import android.view.View import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.widget.FrameLayout import com.android.systemui.customization.R -import com.android.systemui.log.core.MessageBuffer import com.android.systemui.plugins.clocks.AlarmData import com.android.systemui.plugins.clocks.ClockAnimations import com.android.systemui.plugins.clocks.ClockEvents @@ -45,22 +42,19 @@ import kotlin.math.max // TODO(b/364680879): Merge w/ ComposedDigitalLayerController class FlexClockFaceController( - ctx: Context, - private val resources: Resources, - val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources + clockCtx: ClockContext, face: ClockFace, private val isLargeClock: Boolean, - messageBuffer: MessageBuffer, ) : ClockFaceController { override val view: View get() = layerController.view override val config = ClockFaceConfig(hasCustomPositionUpdatedAnimation = true) - override var theme = ThemeConfig(true, assets.seedColor) + override var theme = ThemeConfig(true, clockCtx.settings.seedColor) private val keyguardLargeClockTopMargin = - resources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin) + clockCtx.resources.getDimensionPixelSize(R.dimen.keyguard_large_clock_top_margin) val layerController: SimpleClockLayerController val timespecHandler = DigitalTimespecHandler(DigitalTimespec.TIME_FULL_FORMAT, "hh:mm") @@ -72,23 +66,10 @@ class FlexClockFaceController( layerController = if (isLargeClock) { - ComposedDigitalLayerController( - ctx, - resources, - assets, - layer as ComposedDigitalHandLayer, - messageBuffer, - ) + ComposedDigitalLayerController(clockCtx, layer as ComposedDigitalHandLayer) } else { - val childView = SimpleDigitalClockTextView(ctx, messageBuffer) - SimpleDigitalHandLayerController( - ctx, - resources, - assets, - layer as DigitalHandLayer, - childView, - messageBuffer, - ) + val childView = SimpleDigitalClockTextView(clockCtx) + SimpleDigitalHandLayerController(clockCtx, layer as DigitalHandLayer, childView) } layerController.view.layoutParams = lp } @@ -97,7 +78,7 @@ class FlexClockFaceController( private fun offsetGlyphsForStepClockAnimation( clockStartLeft: Int, direction: Int, - fraction: Float + fraction: Float, ) { (view as? FlexClockView)?.offsetGlyphsForStepClockAnimation( clockStartLeft, diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt index 143b28f1e82b..ebac4b24732b 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/SimpleDigitalHandLayerController.kt @@ -16,8 +16,6 @@ package com.android.systemui.shared.clocks -import android.content.Context -import android.content.res.Resources import android.graphics.Rect import android.view.View import android.view.ViewGroup @@ -25,7 +23,6 @@ import android.widget.RelativeLayout import androidx.annotation.VisibleForTesting import com.android.systemui.customization.R import com.android.systemui.log.core.Logger -import com.android.systemui.log.core.MessageBuffer import com.android.systemui.plugins.clocks.AlarmData import com.android.systemui.plugins.clocks.ClockAnimations import com.android.systemui.plugins.clocks.ClockEvents @@ -42,14 +39,11 @@ import java.util.TimeZone private val TAG = SimpleDigitalHandLayerController::class.simpleName!! open class SimpleDigitalHandLayerController<T>( - private val ctx: Context, - private val resources: Resources, - private val assets: AssetLoader, // TODO(b/364680879): Remove and replace w/ resources + private val clockCtx: ClockContext, private val layer: DigitalHandLayer, override val view: T, - messageBuffer: MessageBuffer, ) : SimpleClockLayerController where T : View, T : SimpleDigitalClockView { - private val logger = Logger(messageBuffer, TAG) + private val logger = Logger(clockCtx.messageBuffer, TAG) val timespec = DigitalTimespecHandler(layer.timespec, layer.dateTimeFormat) @VisibleForTesting @@ -75,12 +69,12 @@ open class SimpleDigitalHandLayerController<T>( layer.alignment.verticalAlignment?.let { view.verticalAlignment = it } layer.alignment.horizontalAlignment?.let { view.horizontalAlignment = it } } - view.applyStyles(assets, layer.style, layer.aodStyle) + view.applyStyles(layer.style, layer.aodStyle) view.id = - ctx.resources.getIdentifier( + clockCtx.resources.getIdentifier( generateDigitalLayerIdString(layer), "id", - ctx.getPackageName(), + clockCtx.context.getPackageName(), ) } @@ -306,8 +300,9 @@ open class SimpleDigitalHandLayerController<T>( val color = when { theme.seedColor != null -> theme.seedColor!! - theme.isDarkTheme -> resources.getColor(android.R.color.system_accent1_100) - else -> resources.getColor(android.R.color.system_accent2_600) + theme.isDarkTheme -> + clockCtx.resources.getColor(android.R.color.system_accent1_100) + else -> clockCtx.resources.getColor(android.R.color.system_accent2_600) } view.updateColor(color) diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt index b09332f34e99..d4eb7677c757 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/DigitalClockFaceView.kt @@ -16,24 +16,23 @@ package com.android.systemui.shared.clocks.view -import android.content.Context import android.graphics.Canvas import android.graphics.Point import android.view.View import android.widget.FrameLayout import androidx.annotation.VisibleForTesting import com.android.systemui.log.core.Logger -import com.android.systemui.log.core.MessageBuffer import com.android.systemui.plugins.clocks.AlarmData import com.android.systemui.plugins.clocks.ClockFontAxisSetting import com.android.systemui.plugins.clocks.WeatherData import com.android.systemui.plugins.clocks.ZenData +import com.android.systemui.shared.clocks.ClockContext import com.android.systemui.shared.clocks.LogUtil import java.util.Locale // TODO(b/364680879): Merge w/ only subclass FlexClockView -abstract class DigitalClockFaceView(ctx: Context, messageBuffer: MessageBuffer) : FrameLayout(ctx) { - protected val logger = Logger(messageBuffer, this::class.simpleName!!) +abstract class DigitalClockFaceView(clockCtx: ClockContext) : FrameLayout(clockCtx.context) { + protected val logger = Logger(clockCtx.messageBuffer, this::class.simpleName!!) get() = field ?: LogUtil.FALLBACK_INIT_LOGGER abstract var digitalClockTextViewMap: MutableMap<Int, SimpleDigitalClockTextView> diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt index 593eba9d05cc..faef18c1e85a 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt @@ -16,31 +16,34 @@ package com.android.systemui.shared.clocks.view -import android.content.Context import android.graphics.Canvas import android.graphics.Point +import android.icu.text.NumberFormat import android.util.MathUtils.constrainedMap import android.view.View import android.view.ViewGroup import android.widget.RelativeLayout import com.android.app.animation.Interpolators import com.android.systemui.customization.R -import com.android.systemui.log.core.MessageBuffer -import com.android.systemui.shared.clocks.AssetLoader +import com.android.systemui.shared.clocks.ClockContext import com.android.systemui.shared.clocks.DigitTranslateAnimator +import java.util.Locale import kotlin.math.abs import kotlin.math.max import kotlin.math.min fun clamp(value: Float, minVal: Float, maxVal: Float): Float = max(min(value, maxVal), minVal) -class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: MessageBuffer) : - DigitalClockFaceView(context, messageBuffer) { +class FlexClockView(clockCtx: ClockContext) : DigitalClockFaceView(clockCtx) { override var digitalClockTextViewMap = mutableMapOf<Int, SimpleDigitalClockTextView>() - val digitLeftTopMap = mutableMapOf<Int, Point>() - var maxSingleDigitSize = Point(-1, -1) - val lockscreenTranslate = Point(0, 0) - var aodTranslate = Point(0, 0) + private val digitLeftTopMap = mutableMapOf<Int, Point>() + + private var maxSingleDigitSize = Point(-1, -1) + private val lockscreenTranslate = Point(0, 0) + private var aodTranslate = Point(0, 0) + + // Does the current language have mono vertical size when displaying numerals + private var isMonoVerticalNumericLineSpacing = true init { setWillNotDraw(false) @@ -49,6 +52,7 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, ) + updateLocale(Locale.getDefault()) } private val digitOffsets = mutableMapOf<Int, Float>() @@ -61,12 +65,19 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me protected override fun calculateSize(widthMeasureSpec: Int, heightMeasureSpec: Int): Point { maxSingleDigitSize = Point(-1, -1) + val bottomLocation: (textView: SimpleDigitalClockTextView) -> Int = { textView -> + if (isMonoVerticalNumericLineSpacing) { + maxSingleDigitSize.y + } else { + (textView.paint.fontMetrics.descent - textView.paint.fontMetrics.ascent).toInt() + } + } + digitalClockTextViewMap.forEach { (_, textView) -> textView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED) maxSingleDigitSize.x = max(maxSingleDigitSize.x, textView.measuredWidth) - maxSingleDigitSize.y = max(maxSingleDigitSize.y, textView.measuredHeight) + maxSingleDigitSize.y = max(bottomLocation(textView), textView.measuredHeight) } - val textView = digitalClockTextViewMap[R.id.HOUR_FIRST_DIGIT]!! aodTranslate = Point(0, 0) return Point( ((maxSingleDigitSize.x + abs(aodTranslate.x)) * 2), @@ -106,6 +117,11 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me } } + override fun onLocaleChanged(locale: Locale) { + updateLocale(locale) + requestLayout() + } + override fun animateDoze(isDozing: Boolean, isAnimated: Boolean) { dozeControlState.animateDoze = { super.animateDoze(isDozing, isAnimated) @@ -166,6 +182,18 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me } } + private fun updateLocale(locale: Locale) { + isMonoVerticalNumericLineSpacing = + !NON_MONO_VERTICAL_NUMERIC_LINE_SPACING_LANGUAGES.any { + val newLocaleNumberFormat = + NumberFormat.getInstance(locale).format(FORMAT_NUMBER.toLong()) + val nonMonoVerticalNumericLineSpaceNumberFormat = + NumberFormat.getInstance(Locale.forLanguageTag(it)) + .format(FORMAT_NUMBER.toLong()) + newLocaleNumberFormat == nonMonoVerticalNumericLineSpaceNumberFormat + } + } + /** * Offsets the textViews of the clock for the step clock animation. * @@ -264,10 +292,18 @@ class FlexClockView(context: Context, val assets: AssetLoader, messageBuffer: Me // Constants for the animation private val MOVE_INTERPOLATOR = Interpolators.EMPHASIZED + private const val FORMAT_NUMBER = 1234567890 + // Total available transition time for each digit, taking into account the step. If step is // 0.1, then digit 0 would animate over 0.0 - 0.7, making availableTime 0.7. private const val AVAILABLE_ANIMATION_TIME = 1.0f - MOVE_DIGIT_STEP * (NUM_DIGITS - 1) + // Add language tags below that do not have vertically mono spaced numerals + private val NON_MONO_VERTICAL_NUMERIC_LINE_SPACING_LANGUAGES = + setOf( + "my", // Burmese + ) + // Use the sign of targetTranslation to control the direction of digit translation fun updateDirectionalTargetTranslate(id: Int, targetTranslation: Point): Point { val outPoint = Point(targetTranslation) diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt index 5c84f2d04ccc..48761c081b9e 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt @@ -17,7 +17,6 @@ package com.android.systemui.shared.clocks.view import android.annotation.SuppressLint -import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint @@ -37,13 +36,11 @@ import android.view.animation.Interpolator import android.widget.TextView import com.android.internal.annotations.VisibleForTesting import com.android.systemui.animation.TextAnimator -import com.android.systemui.animation.TypefaceVariantCache import com.android.systemui.customization.R import com.android.systemui.log.core.Logger -import com.android.systemui.log.core.MessageBuffer import com.android.systemui.plugins.clocks.ClockFontAxisSetting -import com.android.systemui.shared.clocks.AssetLoader import com.android.systemui.shared.clocks.ClockAnimation +import com.android.systemui.shared.clocks.ClockContext import com.android.systemui.shared.clocks.DigitTranslateAnimator import com.android.systemui.shared.clocks.DimensionParser import com.android.systemui.shared.clocks.FontTextStyle @@ -57,18 +54,15 @@ import kotlin.math.min private val TAG = SimpleDigitalClockTextView::class.simpleName!! @SuppressLint("AppCompatCustomView") -open class SimpleDigitalClockTextView( - ctx: Context, - messageBuffer: MessageBuffer, - attrs: AttributeSet? = null, -) : TextView(ctx, attrs), SimpleDigitalClockView { +open class SimpleDigitalClockTextView(clockCtx: ClockContext, attrs: AttributeSet? = null) : + TextView(clockCtx.context, attrs), SimpleDigitalClockView { val lockScreenPaint = TextPaint() override lateinit var textStyle: FontTextStyle lateinit var aodStyle: FontTextStyle private var lsFontVariation = ClockFontAxisSetting.toFVar(DEFAULT_LS_VARIATION) private var aodFontVariation = ClockFontAxisSetting.toFVar(DEFAULT_AOD_VARIATION) - private val parser = DimensionParser(ctx) + private val parser = DimensionParser(clockCtx.context) var maxSingleDigitHeight = -1 var maxSingleDigitWidth = -1 var digitTranslateAnimator: DigitTranslateAnimator? = null @@ -91,33 +85,23 @@ open class SimpleDigitalClockTextView( private val prevTextBounds = Rect() // targetTextBounds holds the state we are interpolating to private val targetTextBounds = Rect() - protected val logger = Logger(messageBuffer, this::class.simpleName!!) + protected val logger = Logger(clockCtx.messageBuffer, this::class.simpleName!!) get() = field ?: LogUtil.FALLBACK_INIT_LOGGER private var aodDozingInterpolator: Interpolator? = null @VisibleForTesting lateinit var textAnimator: TextAnimator - lateinit var typefaceCache: TypefaceVariantCache - private set - - private fun setTypefaceCache(value: TypefaceVariantCache) { - typefaceCache = value - if (this::textAnimator.isInitialized) { - textAnimator.typefaceCache = value - } - } + private val typefaceCache = clockCtx.typefaceCache.getVariantCache("") @VisibleForTesting var textAnimatorFactory: (Layout, () -> Unit) -> TextAnimator = { layout, invalidateCb -> TextAnimator(layout, ClockAnimation.NUM_CLOCK_FONT_ANIMATION_STEPS, invalidateCb).also { - if (this::typefaceCache.isInitialized) { - it.typefaceCache = typefaceCache - } + it.typefaceCache = typefaceCache } } - override var verticalAlignment: VerticalAlignment = VerticalAlignment.CENTER + override var verticalAlignment: VerticalAlignment = VerticalAlignment.BASELINE override var horizontalAlignment: HorizontalAlignment = HorizontalAlignment.LEFT override var isAnimationEnabled = true override var dozeFraction: Float = 0F @@ -258,7 +242,7 @@ open class SimpleDigitalClockTextView( -translation.y.toFloat(), (-translation.x + measuredWidth).toFloat(), (-translation.y + measuredHeight).toFloat(), - Paint().also { it.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT) }, + PORTER_DUFF_XFER_MODE_PAINT, ) canvas.restore() canvas.restore() @@ -403,7 +387,7 @@ open class SimpleDigitalClockTextView( // translation of reference point of text // used for translation when calling textInterpolator - fun getLocalTranslation(): Point { + private fun getLocalTranslation(): Point { val viewHeight = if (isVertical) measuredWidth else measuredHeight val interpolatedTextBounds = updateInterpolatedTextBounds() val localTranslation = Point(0, 0) @@ -429,17 +413,18 @@ open class SimpleDigitalClockTextView( correctedBaseline } VerticalAlignment.BASELINE -> { - localTranslation.y = -lockScreenPaint.strokeWidth.toInt() + // account for max bottom distance of font, so clock doesn't collide with elements + localTranslation.y = + -lockScreenPaint.strokeWidth.toInt() - paint.fontMetrics.descent.toInt() } } return updateXtranslation(localTranslation, interpolatedTextBounds) } - override fun applyStyles(assets: AssetLoader, textStyle: TextStyle, aodStyle: TextStyle?) { + override fun applyStyles(textStyle: TextStyle, aodStyle: TextStyle?) { this.textStyle = textStyle as FontTextStyle val typefaceName = "fonts/" + textStyle.fontFamily - setTypefaceCache(assets.typefaceCache.getVariantCache(typefaceName)) lockScreenPaint.strokeJoin = Paint.Join.ROUND lockScreenPaint.typeface = typefaceCache.getTypefaceForVariant(lsFontVariation) textStyle.fontFeatureSettings?.let { @@ -550,7 +535,9 @@ open class SimpleDigitalClockTextView( } companion object { - val AOD_STROKE_WIDTH = "2dp" + private val PORTER_DUFF_XFER_MODE_PAINT = + Paint().also { it.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT) } + val AOD_COLOR = Color.WHITE val OPTICAL_SIZE_AXIS = ClockFontAxisSetting("opsz", 144f) val DEFAULT_LS_VARIATION = diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt index 3d2ed4a1ef40..e8be28fb8df2 100644 --- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt +++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockView.kt @@ -18,7 +18,6 @@ package com.android.systemui.shared.clocks.view import androidx.annotation.VisibleForTesting import com.android.systemui.plugins.clocks.ClockFontAxisSetting -import com.android.systemui.shared.clocks.AssetLoader import com.android.systemui.shared.clocks.TextStyle interface SimpleDigitalClockView { @@ -29,7 +28,7 @@ interface SimpleDigitalClockView { val textStyle: TextStyle @VisibleForTesting var isAnimationEnabled: Boolean - fun applyStyles(assets: AssetLoader, textStyle: TextStyle, aodStyle: TextStyle?) + fun applyStyles(textStyle: TextStyle, aodStyle: TextStyle?) fun applyTextSize(targetFontSizePx: Float?, constrainedByHeight: Boolean = false) diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt index 57a67973f34f..85bdf9264467 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardDisplayManagerTest.kt @@ -28,7 +28,7 @@ import com.android.systemui.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.navigationbar.NavigationBarController import com.android.systemui.settings.FakeDisplayTracker -import com.android.systemui.shade.data.repository.FakeShadePositionRepository +import com.android.systemui.shade.data.repository.FakeShadeDisplayRepository import com.android.systemui.statusbar.policy.KeyguardStateController import java.util.concurrent.Executor import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -62,7 +62,7 @@ class KeyguardDisplayManagerTest : SysuiTestCase() { mock(ConnectedDisplayKeyguardPresentation::class.java) @Mock private val deviceStateHelper = mock(DeviceStateHelper::class.java) @Mock private val keyguardStateController = mock(KeyguardStateController::class.java) - private val shadePositionRepository = FakeShadePositionRepository() + private val shadePositionRepository = FakeShadeDisplayRepository() private val mainExecutor = Executor { it.run() } private val backgroundExecutor = Executor { it.run() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt index 72163e4d7710..f82c8b0e56e0 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/authentication/data/repository/AuthenticationRepositoryTest.kt @@ -31,7 +31,8 @@ import com.android.systemui.coroutines.collectLastValue import com.android.systemui.coroutines.collectValues import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope -import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake +import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.FakeUserRepository import com.android.systemui.util.mockito.whenever @@ -62,7 +63,7 @@ class AuthenticationRepositoryTest : SysuiTestCase() { private val testScope = kosmos.testScope private val clock = FakeSystemClock() private val userRepository = FakeUserRepository() - private val mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository + private val mobileConnectionsRepository = kosmos.mobileConnectionsRepository private lateinit var underTest: AuthenticationRepository @@ -110,7 +111,7 @@ class AuthenticationRepositoryTest : SysuiTestCase() { .isEqualTo(AuthenticationMethodModel.None) currentSecurityMode = KeyguardSecurityModel.SecurityMode.SimPin - mobileConnectionsRepository.isAnySimSecure.value = true + mobileConnectionsRepository.fake.isAnySimSecure.value = true assertThat(authMethod).isEqualTo(AuthenticationMethodModel.Sim) assertThat(underTest.getAuthenticationMethod()).isEqualTo(AuthenticationMethodModel.Sim) } @@ -199,7 +200,7 @@ class AuthenticationRepositoryTest : SysuiTestCase() { } private fun setSecurityModeAndDispatchBroadcast( - securityMode: KeyguardSecurityModel.SecurityMode, + securityMode: KeyguardSecurityModel.SecurityMode ) { currentSecurityMode = securityMode dispatchBroadcast() @@ -208,23 +209,15 @@ class AuthenticationRepositoryTest : SysuiTestCase() { private fun dispatchBroadcast() { fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly( context, - Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED) + Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED), ) } companion object { private val USER_INFOS = listOf( - UserInfo( - /* id= */ 100, - /* name= */ "First user", - /* flags= */ 0, - ), - UserInfo( - /* id= */ 101, - /* name= */ "Second user", - /* flags= */ 0, - ), + UserInfo(/* id= */ 100, /* name= */ "First user", /* flags= */ 0), + UserInfo(/* id= */ 101, /* name= */ "Second user", /* flags= */ 0), ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt index 566cd70598de..10bf5233e61e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/BouncerActionButtonInteractorTest.kt @@ -35,7 +35,8 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository -import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake +import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository import com.android.systemui.telephony.data.repository.fakeTelephonyRepository import com.android.systemui.testKosmos import com.android.systemui.user.domain.interactor.SelectedUserInteractor @@ -78,7 +79,7 @@ class BouncerActionButtonInteractorTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) - mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository + mobileConnectionsRepository = kosmos.mobileConnectionsRepository.fake overrideResource(R.string.lockscreen_emergency_call, MESSAGE_EMERGENCY_CALL) overrideResource(R.string.lockscreen_return_to_call, MESSAGE_RETURN_TO_CALL) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt index baeb2dd5aa96..0084e18f519f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModelTest.kt @@ -16,38 +16,64 @@ package com.android.systemui.communal.ui.viewmodel -import androidx.test.ext.junit.runners.AndroidJUnit4 +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization import androidx.test.filters.SmallTest +import com.android.compose.animation.scene.ObservableTransitionState +import com.android.compose.animation.scene.SceneKey +import com.android.systemui.Flags.FLAG_SCENE_CONTAINER import com.android.systemui.SysuiTestCase import com.android.systemui.communal.data.repository.fakeCommunalSceneRepository import com.android.systemui.communal.shared.model.CommunalScenes import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.flags.andSceneContainer import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.kosmos.testScope +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @OptIn(ExperimentalCoroutinesApi::class) @SmallTest -@RunWith(AndroidJUnit4::class) -class CommunalTransitionViewModelTest : SysuiTestCase() { +@RunWith(ParameterizedAndroidJunit4::class) +class CommunalTransitionViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { + + companion object { + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return FlagsParameterization.allCombinationsOf().andSceneContainer() + } + } + + init { + mSetFlagsRule.setFlagsParameterization(flags) + } + private val kosmos = testKosmos() private val testScope = kosmos.testScope private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository private val communalSceneRepository = kosmos.fakeCommunalSceneRepository + private val sceneInteractor = kosmos.sceneInteractor private val underTest: CommunalTransitionViewModel by lazy { kosmos.communalTransitionViewModel } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun testIsUmoOnCommunalDuringTransitionBetweenLockscreenAndGlanceableHub() = testScope.runTest { @@ -61,6 +87,7 @@ class CommunalTransitionViewModelTest : SysuiTestCase() { assertThat(isUmoOnCommunal).isFalse() } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun testIsUmoOnCommunalDuringTransitionBetweenDreamingAndGlanceableHub() = testScope.runTest { @@ -74,6 +101,7 @@ class CommunalTransitionViewModelTest : SysuiTestCase() { assertThat(isUmoOnCommunal).isFalse() } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun testIsUmoOnCommunalDuringTransitionBetweenOccludedAndGlanceableHub() = testScope.runTest { @@ -87,6 +115,7 @@ class CommunalTransitionViewModelTest : SysuiTestCase() { assertThat(isUmoOnCommunal).isFalse() } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun isUmoOnCommunal_noLongerVisible_returnsFalse() = testScope.runTest { @@ -103,6 +132,7 @@ class CommunalTransitionViewModelTest : SysuiTestCase() { assertThat(isUmoOnCommunal).isFalse() } + @DisableFlags(FLAG_SCENE_CONTAINER) @Test fun isUmoOnCommunal_idleOnCommunal_returnsTrue() = testScope.runTest { @@ -116,11 +146,25 @@ class CommunalTransitionViewModelTest : SysuiTestCase() { assertThat(isUmoOnCommunal).isTrue() } + @EnableFlags(FLAG_SCENE_CONTAINER) + @Test + fun isUmoOnCommunal_sceneContainerEnabled_idleOnCommunal_returnsTrue() = + testScope.runTest { + val isUmoOnCommunal by collectLastValue(underTest.isUmoOnCommunal) + assertThat(isUmoOnCommunal).isFalse() + + // Change to communal scene. + setIdleScene(Scenes.Communal) + + // isUmoOnCommunal returns true, even without any keyguard transition. + assertThat(isUmoOnCommunal).isTrue() + } + private suspend fun TestScope.enterCommunal(from: KeyguardState) { keyguardTransitionRepository.sendTransitionSteps( from = from, to = KeyguardState.GLANCEABLE_HUB, - testScope + testScope, ) communalSceneRepository.changeScene(CommunalScenes.Communal) runCurrent() @@ -130,9 +174,17 @@ class CommunalTransitionViewModelTest : SysuiTestCase() { keyguardTransitionRepository.sendTransitionSteps( from = KeyguardState.GLANCEABLE_HUB, to = to, - testScope + testScope, ) communalSceneRepository.changeScene(CommunalScenes.Blank) runCurrent() } + + private fun setIdleScene(scene: SceneKey) { + sceneInteractor.changeScene(scene, "test") + val transitionState = + MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(scene)) + sceneInteractor.setTransitionState(transitionState) + testScope.runCurrent() + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt index 6b851cb017e1..5bbd3ffc625a 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt @@ -56,6 +56,7 @@ import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInterac import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer +import com.android.systemui.media.controls.ui.controller.mediaCarouselController import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.settings.fakeUserTracker import com.android.systemui.testKosmos @@ -133,6 +134,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() { accessibilityManager, packageManager, WIDGET_PICKER_PACKAGE_NAME, + kosmos.mediaCarouselController, ) } 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 09daa51a3b37..3eba8ff4b198 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 @@ -69,6 +69,7 @@ import com.android.systemui.kosmos.testDispatcher import com.android.systemui.kosmos.testScope import com.android.systemui.log.logcatLogBuffer import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager +import com.android.systemui.media.controls.ui.controller.mediaCarouselController import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.power.domain.interactor.PowerInteractor.Companion.setAwakeForTest import com.android.systemui.power.domain.interactor.powerInteractor @@ -178,6 +179,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { mediaHost, logcatLogBuffer("CommunalViewModelTest"), metricsLogger, + kosmos.mediaCarouselController, ) } @@ -627,10 +629,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { kosmos.setTransition( sceneTransition = Idle(Scenes.Communal), stateTransition = - TransitionStep( - from = KeyguardState.DREAMING, - to = KeyguardState.GLANCEABLE_HUB - ), + TransitionStep(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB), ) // Then flow is not frozen @@ -647,10 +646,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { kosmos.setTransition( sceneTransition = Idle(Scenes.Lockscreen), stateTransition = - TransitionStep( - from = KeyguardState.GLANCEABLE_HUB, - to = KeyguardState.OCCLUDED - ), + TransitionStep(from = KeyguardState.GLANCEABLE_HUB, to = KeyguardState.OCCLUDED), ) // Then flow is not frozen @@ -735,10 +731,7 @@ class CommunalViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { kosmos.setTransition( sceneTransition = Idle(Scenes.Communal), stateTransition = - TransitionStep( - from = KeyguardState.DREAMING, - to = KeyguardState.GLANCEABLE_HUB - ), + TransitionStep(from = KeyguardState.DREAMING, to = KeyguardState.GLANCEABLE_HUB), ) // Widgets available diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractorTest.kt new file mode 100644 index 000000000000..789178728f18 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractorTest.kt @@ -0,0 +1,181 @@ +/* + * 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.display.domain.interactor + +import android.hardware.display.defaultDisplay +import android.hardware.display.rearDisplay +import android.view.Display +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.display.data.repository.DeviceStateRepository +import com.android.systemui.display.data.repository.FakeDeviceStateRepository +import com.android.systemui.display.data.repository.FakeDisplayRepository +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.Job +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.launch +import kotlinx.coroutines.test.TestScope +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.whenever + +/** atest RearDisplayStateInteractorTest */ +@RunWith(AndroidJUnit4::class) +@SmallTest +class RearDisplayStateInteractorTest : SysuiTestCase() { + + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val fakeDisplayRepository = FakeDisplayRepository() + private val fakeDeviceStateRepository = FakeDeviceStateRepository() + private val rearDisplayStateInteractor = + RearDisplayStateInteractorImpl( + fakeDisplayRepository, + fakeDeviceStateRepository, + kosmos.testDispatcher, + ) + private val emissionTracker = EmissionTracker(rearDisplayStateInteractor, kosmos.testScope) + + @Before + fun setup() { + whenever(kosmos.rearDisplay.flags).thenReturn(Display.FLAG_REAR) + } + + @Test + fun enableRearDisplayWhenDisplayImmediatelyAvailable() = + kosmos.runTest { + emissionTracker.use { tracker -> + fakeDisplayRepository.addDisplay(kosmos.rearDisplay) + assertThat(tracker.enabledCount).isEqualTo(0) + fakeDeviceStateRepository.emit( + DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT + ) + + assertThat(tracker.enabledCount).isEqualTo(1) + assertThat(tracker.lastDisplay).isEqualTo(kosmos.rearDisplay) + } + } + + @Test + fun enableAndDisableRearDisplay() = + kosmos.runTest { + emissionTracker.use { tracker -> + // The fake FakeDeviceStateRepository will always start with state UNKNOWN, thus + // triggering one initial emission + assertThat(tracker.disabledCount).isEqualTo(1) + + fakeDeviceStateRepository.emit( + DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT + ) + + // Adding a non-rear display does not trigger an emission + fakeDisplayRepository.addDisplay(kosmos.defaultDisplay) + assertThat(tracker.enabledCount).isEqualTo(0) + + // Adding a rear display triggers the emission + fakeDisplayRepository.addDisplay(kosmos.rearDisplay) + assertThat(tracker.enabledCount).isEqualTo(1) + assertThat(tracker.lastDisplay).isEqualTo(kosmos.rearDisplay) + + fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.UNFOLDED) + assertThat(tracker.disabledCount).isEqualTo(2) + } + } + + @Test + fun enableRearDisplayShouldOnlyReactToFirstRearDisplay() = + kosmos.runTest { + emissionTracker.use { tracker -> + fakeDeviceStateRepository.emit( + DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT + ) + + // Adding a rear display triggers the emission + fakeDisplayRepository.addDisplay(kosmos.rearDisplay) + assertThat(tracker.enabledCount).isEqualTo(1) + + // Adding additional rear displays does not trigger additional emissions + fakeDisplayRepository.addDisplay(kosmos.rearDisplay) + assertThat(tracker.enabledCount).isEqualTo(1) + } + } + + @Test + fun rearDisplayAddedWhenNoLongerInRdm() = + kosmos.runTest { + emissionTracker.use { tracker -> + fakeDeviceStateRepository.emit( + DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT + ) + fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.UNFOLDED) + + // Adding a rear display when no longer in the correct device state does not trigger + // an emission + fakeDisplayRepository.addDisplay(kosmos.rearDisplay) + assertThat(tracker.enabledCount).isEqualTo(0) + } + } + + @Test + fun rearDisplayDisabledDoesNotSpam() = + kosmos.runTest { + emissionTracker.use { tracker -> + fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.UNFOLDED) + assertThat(tracker.disabledCount).isEqualTo(1) + + // No additional emission + fakeDeviceStateRepository.emit(DeviceStateRepository.DeviceState.FOLDED) + assertThat(tracker.disabledCount).isEqualTo(1) + } + } + + class EmissionTracker(rearDisplayInteractor: RearDisplayStateInteractor, scope: TestScope) : + AutoCloseable { + var enabledCount = 0 + var disabledCount = 0 + var lastDisplay: Display? = null + + val job: Job + + init { + val channel = Channel<RearDisplayStateInteractor.State>(Channel.UNLIMITED) + job = + scope.launch { + rearDisplayInteractor.state.collect { + channel.send(it) + if (it is RearDisplayStateInteractor.State.Enabled) { + enabledCount++ + lastDisplay = it.innerDisplay + } + if (it is RearDisplayStateInteractor.State.Disabled) { + disabledCount++ + } + } + } + } + + override fun close() { + job.cancel() + } + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt index 8062358f670c..a65e7ed48797 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/dreams/DreamOverlayServiceTest.kt @@ -19,7 +19,9 @@ import android.app.WindowConfiguration import android.content.ComponentName import android.content.Intent import android.os.RemoteException +import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.FlagsParameterization import android.service.dreams.Flags import android.service.dreams.IDreamOverlay import android.service.dreams.IDreamOverlayCallback @@ -33,7 +35,6 @@ import android.view.WindowManagerImpl import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.app.viewcapture.ViewCapture import com.android.app.viewcapture.ViewCaptureAwareWindowManager @@ -43,6 +44,7 @@ import com.android.internal.logging.UiEventLogger import com.android.keyguard.KeyguardUpdateMonitor import com.android.keyguard.KeyguardUpdateMonitorCallback import com.android.systemui.Flags.FLAG_COMMUNAL_HUB +import com.android.systemui.Flags.FLAG_SCENE_CONTAINER import com.android.systemui.SysuiTestCase import com.android.systemui.ambient.touch.TouchMonitor import com.android.systemui.ambient.touch.dagger.AmbientTouchComponent @@ -62,12 +64,16 @@ import com.android.systemui.complication.ComplicationLayoutEngine import com.android.systemui.complication.dagger.ComplicationComponent import com.android.systemui.dreams.complication.HideComplicationTouchHandler import com.android.systemui.dreams.dagger.DreamOverlayComponent +import com.android.systemui.flags.andSceneContainer import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.gesture.domain.gestureInteractor import com.android.systemui.kosmos.testScope import com.android.systemui.navigationbar.gestural.domain.GestureInteractor import com.android.systemui.navigationbar.gestural.domain.TaskInfo import com.android.systemui.navigationbar.gestural.domain.TaskMatcher +import com.android.systemui.scene.data.repository.sceneContainerRepository +import com.android.systemui.scene.domain.interactor.sceneInteractor +import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.testKosmos import com.android.systemui.touch.TouchInsetManager import com.android.systemui.util.concurrency.FakeExecutor @@ -98,12 +104,14 @@ import org.mockito.kotlin.spy import org.mockito.kotlin.times import org.mockito.kotlin.verifyNoMoreInteractions import org.mockito.kotlin.whenever +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) -@RunWith(AndroidJUnit4::class) -class DreamOverlayServiceTest : SysuiTestCase() { +@RunWith(ParameterizedAndroidJunit4::class) +class DreamOverlayServiceTest(flags: FlagsParameterization?) : SysuiTestCase() { private val mFakeSystemClock = FakeSystemClock() private val mMainExecutor = FakeExecutor(mFakeSystemClock) private val kosmos = testKosmos() @@ -245,6 +253,10 @@ class DreamOverlayServiceTest : SysuiTestCase() { ) } + init { + mSetFlagsRule.setFlagsParameterization(flags!!) + } + @Before fun setup() { MockitoAnnotations.initMocks(this) @@ -287,6 +299,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { mKeyguardUpdateMonitor, mScrimManager, mCommunalInteractor, + kosmos.sceneInteractor, mSystemDialogsCloser, mUiEventLogger, mTouchInsetManager, @@ -768,6 +781,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { @Test @EnableFlags(Flags.FLAG_DREAM_WAKE_REDIRECT, FLAG_COMMUNAL_HUB) + @DisableFlags(FLAG_SCENE_CONTAINER) @kotlin.Throws(RemoteException::class) fun testTransitionToGlanceableHub() = testScope.runTest { @@ -793,6 +807,35 @@ class DreamOverlayServiceTest : SysuiTestCase() { } @Test + @EnableFlags(Flags.FLAG_DREAM_WAKE_REDIRECT, FLAG_SCENE_CONTAINER, FLAG_COMMUNAL_HUB) + @kotlin.Throws(RemoteException::class) + fun testTransitionToGlanceableHub_sceneContainer() = + testScope.runTest { + // Inform the overlay service of dream starting. Do not show dream complications. + client.startDream( + mWindowParams, + mDreamOverlayCallback, + DREAM_COMPONENT, + false /*isPreview*/, + false, /*shouldShowComplication*/ + ) + mMainExecutor.runAllReady() + + verify(mDreamOverlayCallback).onRedirectWake(false) + clearInvocations(mDreamOverlayCallback) + kosmos.setCommunalAvailable(true) + mMainExecutor.runAllReady() + runCurrent() + verify(mDreamOverlayCallback).onRedirectWake(true) + client.onWakeRequested() + mMainExecutor.runAllReady() + runCurrent() + assertThat(kosmos.sceneContainerRepository.currentScene.value) + .isEqualTo(Scenes.Communal) + verify(mUiEventLogger).log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_DREAM_AWAKE_START) + } + + @Test @EnableFlags(Flags.FLAG_DREAM_WAKE_REDIRECT, FLAG_COMMUNAL_HUB) @Throws(RemoteException::class) fun testRedirectExit() = @@ -911,6 +954,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { // Verifies that the touch handling lifecycle is STARTED even if the dream starts while not // focused. @Test + @DisableFlags(FLAG_SCENE_CONTAINER) fun testLifecycle_dreamNotFocusedOnStart_isStarted() { val transitionState: MutableStateFlow<ObservableTransitionState> = MutableStateFlow(ObservableTransitionState.Idle(CommunalScenes.Blank)) @@ -1024,6 +1068,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { } @Test + @DisableFlags(FLAG_SCENE_CONTAINER) fun testCommunalVisible_setsLifecycleState() { val client = client @@ -1060,6 +1105,7 @@ class DreamOverlayServiceTest : SysuiTestCase() { // Verifies the dream's lifecycle @Test + @DisableFlags(FLAG_SCENE_CONTAINER) fun testLifecycleStarted_whenAnyOcclusion() { val client = client @@ -1256,5 +1302,11 @@ class DreamOverlayServiceTest : SysuiTestCase() { ComponentName("package", "homeControlPanel") private const val DREAM_COMPONENT = "package/dream" private const val WINDOW_NAME = "test" + + @JvmStatic + @Parameters(name = "{0}") + fun getParams(): List<FlagsParameterization> { + return FlagsParameterization.allCombinationsOf(FLAG_COMMUNAL_HUB).andSceneContainer() + } } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt index 5efb6171cdde..f6a6e5465e1b 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModelTest.kt @@ -119,22 +119,6 @@ class TileHapticsViewModelTest : SysuiTestCase() { } @Test - fun onLongClick_whenTileDoesNotHandleLongClick_playsFailureHaptics() = - testScope.runTest { - // WHEN the tile is long-clicked but the tile does not handle a long-click - val state = QSTile.State().apply { handlesLongClick = false } - qsTile.changeState(state) - underTest.setTileInteractionState( - TileHapticsViewModel.TileInteractionState.LONG_CLICKED - ) - runCurrent() - - // THEN the failure token plays - assertThat(msdlPlayer.latestTokenPlayed).isEqualTo(MSDLToken.FAILURE) - assertThat(msdlPlayer.latestPropertiesPlayed).isNull() - } - - @Test fun whenLaunchingFromClick_doesNotPlayHaptics() = testScope.runTest { // WHEN the tile is clicked and its action state changes accordingly diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt index 4e429c34bf2a..69fb03dc6433 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/data/repository/BiometricSettingsRepositoryTest.kt @@ -47,7 +47,8 @@ import com.android.systemui.keyguard.data.repository.BiometricType.SIDE_FINGERPR import com.android.systemui.keyguard.data.repository.BiometricType.UNDER_DISPLAY_FINGERPRINT import com.android.systemui.keyguard.shared.model.DevicePosture import com.android.systemui.res.R -import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake +import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository import com.android.systemui.statusbar.policy.DevicePostureController import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.FakeUserRepository @@ -99,7 +100,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { private lateinit var devicePostureRepository: FakeDevicePostureRepository private lateinit var facePropertyRepository: FakeFacePropertyRepository private lateinit var fingerprintPropertyRepository: FakeFingerprintPropertyRepository - private val mobileConnectionsRepository = kosmos.fakeMobileConnectionsRepository + private val mobileConnectionsRepository = kosmos.mobileConnectionsRepository private lateinit var testDispatcher: TestDispatcher private lateinit var testScope: TestScope @@ -142,7 +143,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { 1, SensorStrength.STRONG, FingerprintSensorType.UDFPS_OPTICAL, - emptyMap() + emptyMap(), ) verify(lockPatternUtils).registerStrongAuthTracker(strongAuthTracker.capture()) verify(authController, times(2)).addCallback(authControllerCallback.capture()) @@ -247,7 +248,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { private fun deviceIsInPostureThatSupportsFaceAuth() { overrideResource( R.integer.config_face_auth_supported_posture, - DevicePostureController.DEVICE_POSTURE_FLIPPED + DevicePostureController.DEVICE_POSTURE_FLIPPED, ) devicePostureRepository.setCurrentPosture(DevicePosture.FLIPPED) } @@ -459,7 +460,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { biometricsAreEnabledBySettings() doNotDisableKeyguardAuthFeatures() - mobileConnectionsRepository.isAnySimSecure.value = false + mobileConnectionsRepository.fake.isAnySimSecure.value = false runCurrent() val isFaceAuthEnabledAndEnrolled by @@ -467,7 +468,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { assertThat(isFaceAuthEnabledAndEnrolled).isTrue() - mobileConnectionsRepository.isAnySimSecure.value = true + mobileConnectionsRepository.fake.isAnySimSecure.value = true runCurrent() assertThat(isFaceAuthEnabledAndEnrolled).isFalse() @@ -485,13 +486,13 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { doNotDisableKeyguardAuthFeatures() faceAuthIsStrongBiometric() biometricsAreEnabledBySettings() - mobileConnectionsRepository.isAnySimSecure.value = false + mobileConnectionsRepository.fake.isAnySimSecure.value = false onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) onNonStrongAuthChanged(false, PRIMARY_USER_ID) assertThat(isFaceAuthCurrentlyAllowed).isTrue() - mobileConnectionsRepository.isAnySimSecure.value = true + mobileConnectionsRepository.fake.isAnySimSecure.value = true assertThat(isFaceAuthCurrentlyAllowed).isFalse() } @@ -584,7 +585,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { testScope.runTest { overrideResource( R.integer.config_face_auth_supported_posture, - DevicePostureController.DEVICE_POSTURE_UNKNOWN + DevicePostureController.DEVICE_POSTURE_UNKNOWN, ) createBiometricSettingsRepository() @@ -597,7 +598,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { testScope.runTest { overrideResource( R.integer.config_face_auth_supported_posture, - DevicePostureController.DEVICE_POSTURE_FLIPPED + DevicePostureController.DEVICE_POSTURE_FLIPPED, ) createBiometricSettingsRepository() @@ -749,7 +750,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { 1, SensorStrength.STRONG, FingerprintSensorType.UDFPS_OPTICAL, - emptyMap() + emptyMap(), ) // Non strong auth is not allowed now, FP is marked strong onStrongAuthChanged(STRONG_AUTH_NOT_REQUIRED, PRIMARY_USER_ID) @@ -761,7 +762,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { 1, SensorStrength.CONVENIENCE, FingerprintSensorType.UDFPS_OPTICAL, - emptyMap() + emptyMap(), ) assertThat(isFingerprintCurrentlyAllowed).isFalse() @@ -769,7 +770,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { 1, SensorStrength.WEAK, FingerprintSensorType.UDFPS_OPTICAL, - emptyMap() + emptyMap(), ) assertThat(isFingerprintCurrentlyAllowed).isFalse() } @@ -791,7 +792,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { 1, SensorStrength.STRONG, FingerprintSensorType.UDFPS_OPTICAL, - emptyMap() + emptyMap(), ) // Non strong auth is not allowed now, FP is marked strong onStrongAuthChanged(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, PRIMARY_USER_ID) @@ -830,7 +831,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { UserInfo( /* id= */ PRIMARY_USER_ID, /* name= */ "primary user", - /* flags= */ UserInfo.FLAG_PRIMARY + /* flags= */ UserInfo.FLAG_PRIMARY, ) private const val ANOTHER_USER_ID = 1 @@ -838,7 +839,7 @@ class BiometricSettingsRepositoryTest : SysuiTestCase() { UserInfo( /* id= */ ANOTHER_USER_ID, /* name= */ "another user", - /* flags= */ UserInfo.FLAG_PRIMARY + /* flags= */ UserInfo.FLAG_PRIMARY, ) } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt index b72668bf5be6..921a8a610c37 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelTest.kt @@ -41,8 +41,8 @@ import com.android.systemui.qs.panels.ui.viewmodel.setConfigurationForMediaInRow import com.android.systemui.res.R import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.statusbar.StatusBarState -import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel import com.android.systemui.statusbar.sysuiStatusBarStateController import com.android.systemui.util.animation.DisappearParameters import com.google.common.truth.Truth.assertThat diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt index bf97afed92f4..959081663b56 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractorTest.kt @@ -27,6 +27,7 @@ import com.android.compose.animation.scene.ObservableTransitionState.Transition. import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.keyguard.shared.model.TransitionState @@ -194,6 +195,24 @@ class SceneContainerOcclusionInteractorTest : SysuiTestCase() { .isFalse() } + @Test + fun invisibleDueToOcclusion_isDreaming_emitsTrue() = + testScope.runTest { + val invisibleDueToOcclusion by collectLastValue(underTest.invisibleDueToOcclusion) + + // Verify that we start with unoccluded + assertWithMessage("Should start unoccluded").that(invisibleDueToOcclusion).isFalse() + + // Start dreaming, which is an occluding activity + showOccludingActivity() + kosmos.keyguardInteractor.setDreaming(true) + + // Verify not invisible when dreaming + assertWithMessage("Should be invisible when dreaming") + .that(invisibleDueToOcclusion) + .isTrue() + } + /** Simulates the appearance of a show-when-locked `Activity` in the foreground. */ private fun TestScope.showOccludingActivity() { keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop( 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 af0274b1caaa..2e074da02103 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 @@ -73,6 +73,7 @@ import com.android.systemui.keyguard.data.repository.fakeTrustRepository import com.android.systemui.keyguard.data.repository.keyguardRepository import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository import com.android.systemui.keyguard.dismissCallbackRegistry +import com.android.systemui.keyguard.domain.interactor.dozeInteractor import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.scenetransition.lockscreenSceneTransitionInteractor @@ -143,6 +144,8 @@ class SceneContainerStartableTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val deviceEntryHapticsInteractor by lazy { kosmos.deviceEntryHapticsInteractor } + private val dozeInteractor by lazy { kosmos.dozeInteractor } + private val keyguardInteractor by lazy { kosmos.keyguardInteractor } private val sceneInteractor by lazy { kosmos.sceneInteractor } private val sceneBackInteractor by lazy { kosmos.sceneBackInteractor } private val bouncerInteractor by lazy { kosmos.bouncerInteractor } @@ -373,6 +376,64 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test + fun hydrateVisibility_whileDreaming() = + testScope.runTest { + val isVisible by collectLastValue(sceneInteractor.isVisible) + + // GIVEN the device is dreaming + val transitionState = + prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Dream) + underTest.start() + assertThat(isVisible).isFalse() + } + + @Test + fun hydrateVisibility_onCommunalWhileOccluded() = + testScope.runTest { + val isVisible by collectLastValue(sceneInteractor.isVisible) + + kosmos.keyguardOcclusionInteractor.setWmNotifiedShowWhenLockedActivityOnTop( + true, + mock(), + ) + prepareState(isDeviceUnlocked = false, initialSceneKey = Scenes.Communal) + underTest.start() + runCurrent() + assertThat(isVisible).isTrue() + } + + @Test + fun hydrateVisibility_inCommunalTransition() = + testScope.runTest { + val isVisible by collectLastValue(sceneInteractor.isVisible) + + // GIVEN the device is dreaming + val transitionState = + prepareState( + authenticationMethod = AuthenticationMethodModel.Pin, + isDeviceUnlocked = false, + initialSceneKey = Scenes.Dream, + ) + underTest.start() + assertThat(isVisible).isFalse() + + // WHEN a transition starts to the communal hub + sceneInteractor.changeScene(Scenes.Dream, "switching to dream for test") + transitionState.value = + ObservableTransitionState.Transition( + fromScene = Scenes.Dream, + toScene = Scenes.Communal, + currentScene = flowOf(Scenes.Dream), + progress = flowOf(0.5f), + isInitiatedByUserInput = true, + isUserInputOngoing = flowOf(false), + ) + runCurrent() + // THEN scenes are visible + assertThat(isVisible).isTrue() + } + + @Test fun startsInLockscreenScene() = testScope.runTest { val currentSceneKey by collectLastValue(sceneInteractor.currentScene) @@ -643,7 +704,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fun switchToAOD_whenAvailable_whenDeviceSleepsLocked() = testScope.runTest { kosmos.lockscreenSceneTransitionInteractor.start() - val asleepState by collectLastValue(kosmos.keyguardInteractor.asleepKeyguardState) + val asleepState by collectLastValue(keyguardInteractor.asleepKeyguardState) val currentTransitionInfo by collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal) val transitionState = @@ -673,7 +734,7 @@ class SceneContainerStartableTest : SysuiTestCase() { fun switchToDozing_whenAodUnavailable_whenDeviceSleepsLocked() = testScope.runTest { kosmos.lockscreenSceneTransitionInteractor.start() - val asleepState by collectLastValue(kosmos.keyguardInteractor.asleepKeyguardState) + val asleepState by collectLastValue(keyguardInteractor.asleepKeyguardState) val currentTransitionInfo by collectLastValue(kosmos.keyguardTransitionRepository.currentTransitionInfoInternal) val transitionState = @@ -2360,6 +2421,66 @@ class SceneContainerStartableTest : SysuiTestCase() { } @Test + fun stayOnLockscreen_whenDozingStarted() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + prepareState() + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + underTest.start() + + // Stay on Lockscreen when dozing and dreaming + dozeInteractor.setIsDozing(true) + keyguardInteractor.setDreaming(true) + kosmos.fakeKeyguardRepository.setDreamingWithOverlay(false) + runCurrent() + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + } + + @Test + fun switchFromLockscreenToDream_whenDreamStarted() = + testScope.runTest { + val currentScene by collectLastValue(sceneInteractor.currentScene) + prepareState() + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + underTest.start() + + powerInteractor.setAwakeForTest() + keyguardInteractor.setDreaming(true) + // Move past initial delay with [KeyguardInteractor#isAbleToDream] + advanceTimeBy(600L) + runCurrent() + assertThat(currentScene).isEqualTo(Scenes.Dream) + } + + @Test + fun switchFromDreamToLockscreen_whenLockedAndDreamStopped() = + testScope.runTest { + keyguardInteractor.setDreaming(true) + val currentScene by collectLastValue(sceneInteractor.currentScene) + prepareState(initialSceneKey = Scenes.Dream) + assertThat(currentScene).isEqualTo(Scenes.Dream) + underTest.start() + + keyguardInteractor.setDreaming(false) + runCurrent() + assertThat(currentScene).isEqualTo(Scenes.Lockscreen) + } + + @Test + fun switchFromDreamToGone_whenUnlockedAndDreamStopped() = + testScope.runTest { + keyguardInteractor.setDreaming(true) + val currentScene by collectLastValue(sceneInteractor.currentScene) + prepareState(initialSceneKey = Scenes.Dream, isDeviceUnlocked = true) + assertThat(currentScene).isEqualTo(Scenes.Dream) + underTest.start() + + keyguardInteractor.setDreaming(false) + runCurrent() + assertThat(currentScene).isEqualTo(Scenes.Gone) + } + + @Test fun replacesLockscreenSceneOnBackStack_whenUnlockdViaAlternateBouncer_fromShade() = testScope.runTest { val transitionState = diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java index 01c17bd6285c..94a19c80dc00 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java @@ -148,7 +148,6 @@ import com.android.systemui.statusbar.QsFrameTranslateController; import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository; import com.android.systemui.statusbar.notification.ConversationNotificationManager; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.HeadsUpTouchHelper; @@ -428,7 +427,7 @@ public class NotificationPanelViewControllerBaseTest extends SysuiTestCase { mShadeInteractor = new ShadeInteractorImpl( mTestScope.getBackgroundScope(), mKosmos.getDeviceProvisioningInteractor(), - new FakeDisableFlagsRepository(), + mKosmos.getDisableFlagsInteractor(), mDozeParameters, mFakeKeyguardRepository, mKeyguardTransitionInteractor, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java index 443595dbdf77..ef132d5a4989 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java @@ -149,7 +149,7 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase { @Mock protected LargeScreenHeaderHelper mLargeScreenHeaderHelper; protected FakeDisableFlagsRepository mDisableFlagsRepository = - new FakeDisableFlagsRepository(); + mKosmos.getFakeDisableFlagsRepository(); protected FakeKeyguardRepository mKeyguardRepository = new FakeKeyguardRepository(); protected FakeShadeRepository mShadeRepository = new FakeShadeRepository(); @@ -185,7 +185,7 @@ public class QuickSettingsControllerImplBaseTest extends SysuiTestCase { mShadeInteractor = new ShadeInteractorImpl( mTestScope.getBackgroundScope(), mKosmos.getDeviceProvisioningInteractor(), - mDisableFlagsRepository, + mKosmos.getDisableFlagsInteractor(), mDozeParameters, mKeyguardRepository, keyguardTransitionInteractor, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt index 46961d4db0f6..ee3f8016c410 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/QuickSettingsControllerImplWithCoroutinesTest.kt @@ -19,7 +19,7 @@ package com.android.systemui.shade import android.app.StatusBarManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest -import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancelChildren @@ -61,7 +61,7 @@ class QuickSettingsControllerImplWithCoroutinesTest : QuickSettingsControllerImp mDisableFlagsRepository.disableFlags.value = DisableFlagsModel( StatusBarManager.DISABLE_NONE, - StatusBarManager.DISABLE2_QUICK_SETTINGS + StatusBarManager.DISABLE2_QUICK_SETTINGS, ) runCurrent() @@ -76,7 +76,7 @@ class QuickSettingsControllerImplWithCoroutinesTest : QuickSettingsControllerImp mDisableFlagsRepository.disableFlags.value = DisableFlagsModel( StatusBarManager.DISABLE_NONE, - StatusBarManager.DISABLE2_NOTIFICATION_SHADE + StatusBarManager.DISABLE2_NOTIFICATION_SHADE, ) runCurrent() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePositionRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt index a9a5cac6112e..4e7839efe2a3 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePositionRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt @@ -34,13 +34,13 @@ import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) -class ShadePositionRepositoryTest : SysuiTestCase() { +class ShadeDisplaysRepositoryTest : SysuiTestCase() { private val kosmos = testKosmos() private val testScope = kosmos.testScope private val commandRegistry = kosmos.commandRegistry private val pw = PrintWriter(StringWriter()) - private val underTest = ShadePositionRepositoryImpl(commandRegistry) + private val underTest = ShadeDisplaysRepositoryImpl(commandRegistry) @Before fun setUp() { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt index f192b59cb9e4..8ef1e568cd58 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt @@ -28,7 +28,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.display.data.repository.FakeDisplayWindowPropertiesRepository import com.android.systemui.display.shared.model.DisplayWindowProperties import com.android.systemui.scene.ui.view.WindowRootView -import com.android.systemui.shade.data.repository.FakeShadePositionRepository +import com.android.systemui.shade.data.repository.FakeShadeDisplayRepository import com.android.systemui.statusbar.phone.ConfigurationForwarder import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.TestScope @@ -50,7 +50,7 @@ import org.mockito.kotlin.whenever class ShadeDisplaysInteractorTest : SysuiTestCase() { private val shadeRootview = mock<WindowRootView>() - private val positionRepository = FakeShadePositionRepository() + private val positionRepository = FakeShadeDisplayRepository() private val defaultContext = mock<Context>() private val secondaryContext = mock<Context>() private val contextStore = FakeDisplayWindowPropertiesRepository() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt index 19ac0cf40160..da652c4e1b5e 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt @@ -37,8 +37,8 @@ import com.android.systemui.power.data.repository.fakePowerRepository import com.android.systemui.power.shared.model.WakeSleepReason import com.android.systemui.power.shared.model.WakefulnessState import com.android.systemui.shade.shadeTestUtil -import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel import com.android.systemui.statusbar.phone.dozeParameters import com.android.systemui.statusbar.policy.data.repository.fakeDeviceProvisioningRepository import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt index 907c68440b55..cd078211f934 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepositoryTest.kt @@ -32,7 +32,7 @@ import com.android.systemui.log.LogBufferFactory import com.android.systemui.res.R import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.disableflags.DisableFlagsLogger -import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt index 79ff4be253e1..7eac7e86e372 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractorTest.kt @@ -21,8 +21,8 @@ import com.android.systemui.SysUITestComponent import com.android.systemui.SysUITestModule import com.android.systemui.SysuiTestCase import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel import com.google.common.truth.Truth.assertThat import dagger.BindsInstance import dagger.Component @@ -51,10 +51,7 @@ class NotificationAlertsInteractorTest : SysuiTestCase() { fun disableFlags_notifAlertsNotDisabled_notifAlertsEnabledTrue() = with(testComponent) { disableFlags.disableFlags.value = - DisableFlagsModel( - StatusBarManager.DISABLE_NONE, - StatusBarManager.DISABLE2_NONE, - ) + DisableFlagsModel(StatusBarManager.DISABLE_NONE, StatusBarManager.DISABLE2_NONE) assertThat(underTest.areNotificationAlertsEnabled()).isTrue() } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt index f6d439ab2639..5a77f3d40e82 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.pipeline.mobile.domain.interactor import android.os.ParcelUuid -import android.telephony.SubscriptionManager import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET @@ -25,91 +24,78 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.mobile.MobileMappings import com.android.systemui.SysuiTestCase -import com.android.systemui.coroutines.collectLastValue -import com.android.systemui.flags.FakeFeatureFlagsClassic import com.android.systemui.flags.Flags -import com.android.systemui.log.table.logcatTableLogBuffer +import com.android.systemui.flags.fake +import com.android.systemui.flags.featureFlagsClassic +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runCurrent +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository -import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository -import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy +import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake +import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepositoryLogbufferName import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot -import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository +import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository +import com.android.systemui.statusbar.pipeline.shared.data.repository.fake import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository import com.android.systemui.testKosmos import com.android.systemui.util.CarrierConfigTracker -import com.android.systemui.util.mockito.mock -import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import java.util.UUID import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.StandardTestDispatcher -import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceTimeBy -import kotlinx.coroutines.test.runCurrent -import kotlinx.coroutines.test.runTest -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.Mock -import org.mockito.MockitoAnnotations +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever @OptIn(ExperimentalCoroutinesApi::class) @SmallTest @RunWith(AndroidJUnit4::class) class MobileIconsInteractorTest : SysuiTestCase() { - private val kosmos = testKosmos() - - private lateinit var underTest: MobileIconsInteractor - private lateinit var connectivityRepository: FakeConnectivityRepository - private lateinit var connectionsRepository: FakeMobileConnectionsRepository - private val userSetupRepository = FakeUserSetupRepository() - private val mobileMappingsProxy = FakeMobileMappingsProxy() - private val flags = - FakeFeatureFlagsClassic().apply { - set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true) + private val kosmos by lazy { + testKosmos().apply { + mobileConnectionsRepositoryLogbufferName = "MobileIconsInteractorTest" + mobileConnectionsRepository.fake.run { + setMobileConnectionRepositoryMap( + mapOf( + SUB_1_ID to CONNECTION_1, + SUB_2_ID to CONNECTION_2, + SUB_3_ID to CONNECTION_3, + SUB_4_ID to CONNECTION_4, + ) + ) + setActiveMobileDataSubscriptionId(SUB_1_ID) + } + featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true) } + } - private val testDispatcher = StandardTestDispatcher() - private val testScope = TestScope(testDispatcher) - - private val tableLogBuffer = logcatTableLogBuffer(kosmos, "MobileIconsInteractorTest") - - @Mock private lateinit var carrierConfigTracker: CarrierConfigTracker - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - - connectivityRepository = FakeConnectivityRepository() - - connectionsRepository = FakeMobileConnectionsRepository(mobileMappingsProxy, tableLogBuffer) - connectionsRepository.setMobileConnectionRepositoryMap( - mapOf( - SUB_1_ID to CONNECTION_1, - SUB_2_ID to CONNECTION_2, - SUB_3_ID to CONNECTION_3, - SUB_4_ID to CONNECTION_4, - ) + // shortcut rename + private val Kosmos.connectionsRepository by Fixture { mobileConnectionsRepository.fake } + + private val Kosmos.carrierConfigTracker by Fixture { mock<CarrierConfigTracker>() } + + private val Kosmos.underTest by Fixture { + MobileIconsInteractorImpl( + mobileConnectionsRepository, + carrierConfigTracker, + tableLogger = mock(), + connectivityRepository, + FakeUserSetupRepository(), + testScope.backgroundScope, + context, + featureFlagsClassic, ) - connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID) - - underTest = - MobileIconsInteractorImpl( - connectionsRepository, - carrierConfigTracker, - tableLogger = mock(), - connectivityRepository, - userSetupRepository, - testScope.backgroundScope, - context, - flags, - ) } @Test fun filteredSubscriptions_default() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.filteredSubscriptions) assertThat(latest).isEqualTo(listOf<SubscriptionModel>()) @@ -118,7 +104,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { // Based on the logic from the old pipeline, we'll never filter subs when there are more than 2 @Test fun filteredSubscriptions_moreThanTwo_doesNotFilter() = - testScope.runTest { + kosmos.runTest { connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP)) connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID) @@ -129,7 +115,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() = - testScope.runTest { + kosmos.runTest { connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2)) val latest by collectLastValue(underTest.filteredSubscriptions) @@ -139,7 +125,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_opportunistic_differentGroups_doesNotFilter() = - testScope.runTest { + kosmos.runTest { connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP)) connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID) @@ -150,7 +136,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_opportunistic_nonGrouped_doesNotFilter() = - testScope.runTest { + kosmos.runTest { val (sub1, sub2) = createSubscriptionPair( subscriptionIds = Pair(SUB_1_ID, SUB_2_ID), @@ -167,7 +153,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_3() = - testScope.runTest { + kosmos.runTest { val (sub3, sub4) = createSubscriptionPair( subscriptionIds = Pair(SUB_3_ID, SUB_4_ID), @@ -187,7 +173,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_4() = - testScope.runTest { + kosmos.runTest { val (sub3, sub4) = createSubscriptionPair( subscriptionIds = Pair(SUB_3_ID, SUB_4_ID), @@ -207,7 +193,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_active_1() = - testScope.runTest { + kosmos.runTest { val (sub1, sub3) = createSubscriptionPair( subscriptionIds = Pair(SUB_1_ID, SUB_3_ID), @@ -228,7 +214,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_nonActive_1() = - testScope.runTest { + kosmos.runTest { val (sub1, sub3) = createSubscriptionPair( subscriptionIds = Pair(SUB_1_ID, SUB_3_ID), @@ -249,7 +235,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_vcnSubId_agreesWithActiveSubId_usesActiveAkaVcnSub() = - testScope.runTest { + kosmos.runTest { val (sub1, sub3) = createSubscriptionPair( subscriptionIds = Pair(SUB_1_ID, SUB_3_ID), @@ -258,7 +244,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { ) connectionsRepository.setSubscriptions(listOf(sub1, sub3)) connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID) - connectivityRepository.vcnSubId.value = SUB_3_ID + kosmos.connectivityRepository.fake.vcnSubId.value = SUB_3_ID whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) .thenReturn(false) @@ -269,7 +255,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_vcnSubId_disagreesWithActiveSubId_usesVcnSub() = - testScope.runTest { + kosmos.runTest { val (sub1, sub3) = createSubscriptionPair( subscriptionIds = Pair(SUB_1_ID, SUB_3_ID), @@ -278,7 +264,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { ) connectionsRepository.setSubscriptions(listOf(sub1, sub3)) connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID) - connectivityRepository.vcnSubId.value = SUB_1_ID + kosmos.connectivityRepository.fake.vcnSubId.value = SUB_1_ID whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) .thenReturn(false) @@ -289,9 +275,9 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_doesNotFilterProvisioningWhenFlagIsFalse() = - testScope.runTest { + kosmos.runTest { // GIVEN the flag is false - flags.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false) + featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false) // GIVEN 1 sub that is in PROFILE_CLASS_PROVISIONING val sub1 = @@ -313,7 +299,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_filtersOutProvisioningSubs() = - testScope.runTest { + kosmos.runTest { val sub1 = SubscriptionModel( subscriptionId = SUB_1_ID, @@ -326,7 +312,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { subscriptionId = SUB_2_ID, isOpportunistic = false, carrierName = "Carrier 2", - profileClass = SubscriptionManager.PROFILE_CLASS_PROVISIONING, + profileClass = PROFILE_CLASS_PROVISIONING, ) connectionsRepository.setSubscriptions(listOf(sub1, sub2)) @@ -339,7 +325,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { /** Note: I'm not sure if this will ever be the case, but we can test it at least */ @Test fun filteredSubscriptions_filtersOutProvisioningSubsBeforeOpportunistic() = - testScope.runTest { + kosmos.runTest { // This is a contrived test case, where the active subId is the one that would // also be filtered by opportunistic filtering. @@ -376,7 +362,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_groupedPairAndNonProvisioned_groupedFilteringStillHappens() = - testScope.runTest { + kosmos.runTest { // Grouped filtering only happens when the list of subs is length 2. In this case // we'll show that filtering of provisioning subs happens before, and thus grouped // filtering happens even though the unfiltered list is length 3 @@ -406,7 +392,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_subNotExclusivelyNonTerrestrial_hasSub() = - testScope.runTest { + kosmos.runTest { val notExclusivelyNonTerrestrialSub = SubscriptionModel( isExclusivelyNonTerrestrial = false, @@ -424,7 +410,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_subExclusivelyNonTerrestrial_doesNotHaveSub() = - testScope.runTest { + kosmos.runTest { val exclusivelyNonTerrestrialSub = SubscriptionModel( isExclusivelyNonTerrestrial = true, @@ -442,7 +428,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscription_mixOfExclusivelyNonTerrestrialAndOther_hasOtherSubsOnly() = - testScope.runTest { + kosmos.runTest { val exclusivelyNonTerrestrialSub = SubscriptionModel( isExclusivelyNonTerrestrial = true, @@ -476,7 +462,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun filteredSubscriptions_exclusivelyNonTerrestrialSub_andOpportunistic_bothFiltersHappen() = - testScope.runTest { + kosmos.runTest { // Exclusively non-terrestrial sub val exclusivelyNonTerrestrialSub = SubscriptionModel( @@ -507,7 +493,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun activeDataConnection_turnedOn() = - testScope.runTest { + kosmos.runTest { CONNECTION_1.setDataEnabled(true) val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled) @@ -517,7 +503,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun activeDataConnection_turnedOff() = - testScope.runTest { + kosmos.runTest { CONNECTION_1.setDataEnabled(true) val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled) @@ -528,7 +514,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun activeDataConnection_invalidSubId() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled) connectionsRepository.setActiveMobileDataSubscriptionId(INVALID_SUBSCRIPTION_ID) @@ -539,7 +525,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun failedConnection_default_validated_notFailed() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDefaultConnectionFailed) connectionsRepository.mobileIsDefault.value = true @@ -550,7 +536,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun failedConnection_notDefault_notValidated_notFailed() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDefaultConnectionFailed) connectionsRepository.mobileIsDefault.value = false @@ -561,7 +547,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun failedConnection_default_notValidated_failed() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDefaultConnectionFailed) connectionsRepository.mobileIsDefault.value = true @@ -572,7 +558,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun failedConnection_carrierMergedDefault_notValidated_failed() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDefaultConnectionFailed) connectionsRepository.hasCarrierMergedConnection.value = true @@ -584,7 +570,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { /** Regression test for b/275076959. */ @Test fun failedConnection_dataSwitchInSameGroup_notFailed() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDefaultConnectionFailed) connectionsRepository.mobileIsDefault.value = true @@ -602,7 +588,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun failedConnection_dataSwitchNotInSameGroup_isFailed() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDefaultConnectionFailed) connectionsRepository.mobileIsDefault.value = true @@ -618,7 +604,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun alwaysShowDataRatIcon_configHasTrue() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.alwaysShowDataRatIcon) val config = MobileMappings.Config() @@ -630,7 +616,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun alwaysShowDataRatIcon_configHasFalse() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.alwaysShowDataRatIcon) val config = MobileMappings.Config() @@ -642,7 +628,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun alwaysUseCdmaLevel_configHasTrue() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.alwaysUseCdmaLevel) val config = MobileMappings.Config() @@ -654,7 +640,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun alwaysUseCdmaLevel_configHasFalse() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.alwaysUseCdmaLevel) val config = MobileMappings.Config() @@ -666,7 +652,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun isSingleCarrier_zeroSubscriptions_false() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isSingleCarrier) connectionsRepository.setSubscriptions(emptyList()) @@ -676,7 +662,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun isSingleCarrier_oneSubscription_true() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isSingleCarrier) connectionsRepository.setSubscriptions(listOf(SUB_1)) @@ -686,7 +672,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun isSingleCarrier_twoSubscriptions_false() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isSingleCarrier) connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2)) @@ -696,7 +682,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun isSingleCarrier_updates() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isSingleCarrier) connectionsRepository.setSubscriptions(listOf(SUB_1)) @@ -708,7 +694,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.mobileIsDefault) connectionsRepository.mobileIsDefault.value = false @@ -719,7 +705,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun mobileIsDefault_mobileTrueAndCarrierMergedFalse_true() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.mobileIsDefault) connectionsRepository.mobileIsDefault.value = true @@ -731,7 +717,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { /** Regression test for b/272586234. */ @Test fun mobileIsDefault_mobileFalseAndCarrierMergedTrue_true() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.mobileIsDefault) connectionsRepository.mobileIsDefault.value = false @@ -742,7 +728,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun mobileIsDefault_updatesWhenRepoUpdates() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.mobileIsDefault) connectionsRepository.mobileIsDefault.value = true @@ -760,7 +746,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun dataSwitch_inSameGroup_validatedMatchesPreviousValue_expiresAfter2s() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDefaultConnectionFailed) connectionsRepository.mobileIsDefault.value = true @@ -774,17 +760,17 @@ class MobileIconsInteractorTest : SysuiTestCase() { // After 1s, the force validation bit is still present, so the connection is not marked // as failed - advanceTimeBy(1000) + testScope.advanceTimeBy(1000) assertThat(latest).isFalse() // After 2s, the force validation expires so the connection updates to failed - advanceTimeBy(1001) + testScope.advanceTimeBy(1001) assertThat(latest).isTrue() } @Test fun dataSwitch_inSameGroup_notValidated_immediatelyMarkedAsFailed() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDefaultConnectionFailed) connectionsRepository.mobileIsDefault.value = true @@ -798,7 +784,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun dataSwitch_loseValidation_thenSwitchHappens_clearsForcedBit() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDefaultConnectionFailed) // GIVEN the network starts validated @@ -819,17 +805,17 @@ class MobileIconsInteractorTest : SysuiTestCase() { // THEN the forced validation bit is still used... assertThat(latest).isFalse() - advanceTimeBy(1000) + testScope.advanceTimeBy(1000) assertThat(latest).isFalse() // ... but expires after 2s - advanceTimeBy(1001) + testScope.advanceTimeBy(1001) assertThat(latest).isTrue() } @Test fun dataSwitch_whileAlreadyForcingValidation_resetsClock() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDefaultConnectionFailed) connectionsRepository.mobileIsDefault.value = true connectionsRepository.defaultConnectionIsValidated.value = true @@ -837,7 +823,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { connectionsRepository.activeSubChangedInGroupEvent.emit(Unit) - advanceTimeBy(1000) + testScope.advanceTimeBy(1000) // WHEN another change in same group event happens connectionsRepository.activeSubChangedInGroupEvent.emit(Unit) @@ -847,37 +833,37 @@ class MobileIconsInteractorTest : SysuiTestCase() { // THEN the forced validation remains for exactly 2 more seconds from now // 1.500s from second event - advanceTimeBy(1500) + testScope.advanceTimeBy(1500) assertThat(latest).isFalse() // 2.001s from the second event - advanceTimeBy(501) + testScope.advanceTimeBy(501) assertThat(latest).isTrue() } @Test fun isForceHidden_repoHasMobileHidden_true() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isForceHidden) - connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE)) + kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE)) assertThat(latest).isTrue() } @Test fun isForceHidden_repoDoesNotHaveMobileHidden_false() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isForceHidden) - connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI)) + kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI)) assertThat(latest).isFalse() } @Test fun iconInteractor_cachedPerSubId() = - testScope.runTest { + kosmos.runTest { val interactor1 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID) val interactor2 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID) @@ -887,7 +873,7 @@ class MobileIconsInteractorTest : SysuiTestCase() { @Test fun deviceBasedEmergencyMode_emergencyCallsOnly_followsDeviceServiceStateFromRepo() = - testScope.runTest { + kosmos.runTest { val latest by collectLastValue(underTest.isDeviceInEmergencyCallsOnlyMode) connectionsRepository.isDeviceEmergencyCallCapable.value = true diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt index 46f822aae7b8..db24d4bc8070 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorTest.kt @@ -21,18 +21,18 @@ import android.app.StatusBarManager.DISABLE_CLOCK import android.app.StatusBarManager.DISABLE_NONE import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS import android.app.StatusBarManager.DISABLE_SYSTEM_INFO -import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope -import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlin.test.Test import kotlinx.coroutines.test.runTest -import org.junit.runner.RunWith; +import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt index c4d2569bba89..b9cdd06de5a2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt @@ -58,8 +58,8 @@ import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsVie import com.android.systemui.statusbar.data.model.StatusBarMode import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID import com.android.systemui.statusbar.data.repository.fakeStatusBarModeRepository -import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel import com.android.systemui.statusbar.events.data.repository.systemStatusEventAnimationRepository import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.AnimatingIn import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.AnimatingOut diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt index d823bf57c824..4eef308a2772 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImplTest.kt @@ -27,10 +27,14 @@ import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID import android.testing.TestableLooper +import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.Flags.FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.kosmos.testDispatcher +import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher import com.android.systemui.log.LogBuffer import com.android.systemui.log.table.logcatTableLogBuffer import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory @@ -40,9 +44,7 @@ import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkMode import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry import com.android.systemui.testKosmos import com.android.systemui.user.data.repository.fakeUserRepository -import com.android.systemui.user.data.repository.userRepository import com.android.systemui.util.concurrency.FakeExecutor -import com.android.systemui.util.mockito.argumentCaptor import com.android.systemui.util.time.fakeSystemClock import com.android.wifitrackerlib.HotspotNetworkEntry import com.android.wifitrackerlib.HotspotNetworkEntry.DeviceType @@ -53,31 +55,23 @@ import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_MIN import com.android.wifitrackerlib.WifiEntry.WIFI_LEVEL_UNREACHABLE import com.android.wifitrackerlib.WifiPickerTracker import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.test.StandardTestDispatcher -import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.runCurrent import kotlinx.coroutines.test.runTest import org.junit.Before import org.junit.Test +import org.junit.runner.RunWith import org.mockito.kotlin.any -import org.mockito.kotlin.capture +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.mock -import org.mockito.kotlin.times +import org.mockito.kotlin.never +import org.mockito.kotlin.reset import org.mockito.kotlin.verify import org.mockito.kotlin.whenever -/** - * Note: Most of these tests are duplicates of [WifiRepositoryImplTest] tests. - * - * Any new tests added here may also need to be added to [WifiRepositoryImplTest]. - */ -@Suppress("EXPERIMENTAL_IS_NOT_ENABLED") -@OptIn(ExperimentalCoroutinesApi::class) @SmallTest +@RunWith(AndroidJUnit4::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) -class WifiRepositoryImplTest() : SysuiTestCase() { - private val kosmos = testKosmos() +class WifiRepositoryImplTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() private val userRepository = kosmos.fakeUserRepository // Using lazy means that the class will only be constructed once it's fetched. Because the @@ -108,13 +102,13 @@ class WifiRepositoryImplTest() : SysuiTestCase() { private val callbackCaptor = argumentCaptor<WifiPickerTracker.WifiPickerTrackerCallback>() - private val dispatcher = StandardTestDispatcher() - private val testScope = TestScope(dispatcher) + private val dispatcher = kosmos.testDispatcher + private val testScope = kosmos.testScope @Before fun setUp() { userRepository.setUserInfos(listOf(PRIMARY_USER, ANOTHER_USER)) - whenever(wifiPickerTrackerFactory.create(any(), any(), capture(callbackCaptor), any())) + whenever(wifiPickerTrackerFactory.create(any(), any(), callbackCaptor.capture(), any())) .thenReturn(wifiPickerTracker) } @@ -122,7 +116,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() { fun wifiPickerTrackerCreation_scansDisabled() = testScope.runTest { collectLastValue(underTest.wifiNetwork) - testScope.runCurrent() verify(wifiPickerTracker).disableScanning() } @@ -1001,7 +994,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() { mock<WifiEntry>().apply { whenever(this.isPrimaryNetwork).thenReturn(false) } whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry) getCallback().onWifiEntriesChanged() - testScope.runCurrent() assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() } @@ -1017,7 +1009,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() { } whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry) getCallback().onWifiEntriesChanged() - testScope.runCurrent() assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() } @@ -1034,7 +1025,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() { } whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry) getCallback().onWifiEntriesChanged() - testScope.runCurrent() assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() } @@ -1051,7 +1041,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() { } whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry) getCallback().onWifiEntriesChanged() - testScope.runCurrent() assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() } @@ -1068,7 +1057,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() { } whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry) getCallback().onWifiEntriesChanged() - testScope.runCurrent() assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() } @@ -1085,7 +1073,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() { } whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry) getCallback().onWifiEntriesChanged() - testScope.runCurrent() assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue() } @@ -1103,14 +1090,12 @@ class WifiRepositoryImplTest() : SysuiTestCase() { } whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(wifiEntry) getCallback().onWifiEntriesChanged() - testScope.runCurrent() assertThat(underTest.isWifiConnectedWithValidSsid()).isTrue() // WHEN the network is lost whenever(wifiPickerTracker.connectedWifiEntry).thenReturn(null) getCallback().onWifiEntriesChanged() - testScope.runCurrent() // THEN the isWifiConnected updates assertThat(underTest.isWifiConnectedWithValidSsid()).isFalse() @@ -1216,9 +1201,6 @@ class WifiRepositoryImplTest() : SysuiTestCase() { assertThat(latest).isEmpty() } - // TODO(b/371586248): This test currently require currentUserContext to be public for testing, - // this needs to - // be updated to capture the argument instead so currentUserContext can be private. @Test @EnableFlags(FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT) fun oneUserVerifyCreatingWifiPickerTracker_multiuserFlagEnabled() = @@ -1230,16 +1212,16 @@ class WifiRepositoryImplTest() : SysuiTestCase() { ) userRepository.setSelectedUserInfo(PRIMARY_USER) - runCurrent() - val currentUserContext by collectLastValue(underTest.selectedUserContext) - assertThat(currentUserContext).isEqualTo(primaryUserMockContext) - verify(wifiPickerTrackerFactory).create(any(), any(), any(), any()) + collectLastValue(underTest.wifiNetwork) + + val contextCaptor = argumentCaptor<Context>() + verify(wifiPickerTrackerFactory).create(contextCaptor.capture(), any(), any(), any()) + // If the flag is on, verify that we use the context from #createContextAsUser and we + // do NOT use the top-level context + assertThat(contextCaptor.firstValue).isEqualTo(primaryUserMockContext) } - // TODO(b/371586248): This test currently require currentUserContext to be public for testing, - // this needs to - // be updated to capture the argument instead so currentUserContext can be private. @Test @EnableFlags(FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT) fun changeUserVerifyCreatingWifiPickerTracker_multiuserEnabled() = @@ -1249,32 +1231,30 @@ class WifiRepositoryImplTest() : SysuiTestCase() { UserHandle.of(PRIMARY_USER_ID), primaryUserMockContext, ) - - runCurrent() userRepository.setSelectedUserInfo(PRIMARY_USER) - runCurrent() - val currentUserContext by collectLastValue(underTest.selectedUserContext) - assertThat(currentUserContext).isEqualTo(primaryUserMockContext) + collectLastValue(underTest.wifiNetwork) + + val contextCaptor = argumentCaptor<Context>() + verify(wifiPickerTrackerFactory).create(contextCaptor.capture(), any(), any(), any()) + assertThat(contextCaptor.firstValue).isEqualTo(primaryUserMockContext) + reset(wifiPickerTrackerFactory) + + // WHEN we switch to a different user val otherUserMockContext = mock<Context>() mContext.prepareCreateContextAsUser( UserHandle.of(ANOTHER_USER_ID), otherUserMockContext, ) - - runCurrent() userRepository.setSelectedUserInfo(ANOTHER_USER) - runCurrent() - val otherUserContext by collectLastValue(underTest.selectedUserContext) - assertThat(otherUserContext).isEqualTo(otherUserMockContext) - verify(wifiPickerTrackerFactory, times(2)).create(any(), any(), any(), any()) + // THEN we use the different user's context to create WifiPickerTracker + val newCaptor = argumentCaptor<Context>() + verify(wifiPickerTrackerFactory).create(newCaptor.capture(), any(), any(), any()) + assertThat(newCaptor.firstValue).isEqualTo(otherUserMockContext) } - // TODO(b/371586248): This test currently require currentUserContext to be public for testing, - // this needs to - // be updated to capture the argument instead so currentUserContext can be private. @Test @DisableFlags(FLAG_MULTIUSER_WIFI_PICKER_TRACKER_SUPPORT) fun changeUserVerifyCreatingWifiPickerTracker_multiuserDisabled() = @@ -1285,36 +1265,39 @@ class WifiRepositoryImplTest() : SysuiTestCase() { primaryUserMockContext, ) - runCurrent() userRepository.setSelectedUserInfo(PRIMARY_USER) - runCurrent() - val currentUserContext by collectLastValue(underTest.selectedUserContext) - assertThat(currentUserContext).isEqualTo(primaryUserMockContext) + collectLastValue(underTest.wifiNetwork) + + val contextCaptor = argumentCaptor<Context>() + verify(wifiPickerTrackerFactory).create(contextCaptor.capture(), any(), any(), any()) + // If the flag is off, verify that we do NOT use the context from #createContextAsUser + // and we instead use the top-level context + assertThat(contextCaptor.firstValue).isNotEqualTo(primaryUserMockContext) + assertThat(contextCaptor.firstValue).isEqualTo(mContext) + + reset(wifiPickerTrackerFactory) + // WHEN we switch to a different user val otherUserMockContext = mock<Context>() mContext.prepareCreateContextAsUser( UserHandle.of(ANOTHER_USER_ID), otherUserMockContext, ) - - runCurrent() userRepository.setSelectedUserInfo(ANOTHER_USER) - runCurrent() - verify(wifiPickerTrackerFactory, times(1)).create(any(), any(), any(), any()) + // THEN we do NOT re-create WifiPickerTracker because the multiuser flag is off + verify(wifiPickerTrackerFactory, never()).create(any(), any(), any(), any()) } private fun getCallback(): WifiPickerTracker.WifiPickerTrackerCallback { - testScope.runCurrent() - return callbackCaptor.value + return callbackCaptor.firstValue } private fun getTrafficStateCallback(): WifiManager.TrafficStateCallback { - testScope.runCurrent() val callbackCaptor = argumentCaptor<WifiManager.TrafficStateCallback>() verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture()) - return callbackCaptor.value!! + return callbackCaptor.firstValue } private fun createHotspotWithType(@DeviceType type: Int): HotspotNetworkEntry { @@ -1325,10 +1308,9 @@ class WifiRepositoryImplTest() : SysuiTestCase() { } private fun getScanResultsCallback(): WifiManager.ScanResultsCallback { - testScope.runCurrent() val callbackCaptor = argumentCaptor<WifiManager.ScanResultsCallback>() verify(wifiManager).registerScanResultsCallback(any(), callbackCaptor.capture()) - return callbackCaptor.value!! + return callbackCaptor.firstValue } private companion object { diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt index 0e32c9526df2..e686edec8514 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/ui/dialog/viewmodel/ModesDialogViewModelTest.kt @@ -24,6 +24,7 @@ import android.content.applicationContext import android.provider.Settings import android.service.notification.SystemZenRules import android.service.notification.ZenModeConfig +import android.service.notification.ZenModeConfig.ScheduleInfo import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.settingslib.notification.modes.TestModeBuilder @@ -65,6 +66,7 @@ class ModesDialogViewModelTest : SysuiTestCase() { private lateinit var underTest: ModesDialogViewModel private lateinit var timeScheduleMode: ZenMode + private lateinit var timeScheduleInfo: ScheduleInfo @Before fun setUp() { @@ -78,18 +80,18 @@ class ModesDialogViewModelTest : SysuiTestCase() { kosmos.mockModesDialogEventLogger, ) - val scheduleInfo = ZenModeConfig.ScheduleInfo() - scheduleInfo.days = intArrayOf(Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY) - scheduleInfo.startHour = 11 - scheduleInfo.endHour = 15 + timeScheduleInfo = ZenModeConfig.ScheduleInfo() + timeScheduleInfo.days = intArrayOf(Calendar.MONDAY, Calendar.TUESDAY, Calendar.WEDNESDAY) + timeScheduleInfo.startHour = 11 + timeScheduleInfo.endHour = 15 timeScheduleMode = TestModeBuilder() .setPackage(SystemZenRules.PACKAGE_ANDROID) .setType(AutomaticZenRule.TYPE_SCHEDULE_TIME) .setManualInvocationAllowed(true) - .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo)) + .setConditionId(ZenModeConfig.toScheduleConditionId(timeScheduleInfo)) .setTriggerDescription( - SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, scheduleInfo) + SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, timeScheduleInfo) ) .build() } @@ -358,7 +360,7 @@ class ModesDialogViewModelTest : SysuiTestCase() { assertThat(tiles!![3].subtext).isEqualTo("Off") assertThat(tiles!![4].subtext).isEqualTo("On") assertThat(tiles!![5].subtext).isEqualTo("Not set") - assertThat(tiles!![6].subtext).isEqualTo("Mon - Wed, 11:00 AM - 3:00 PM") + assertThat(tiles!![6].subtext).isEqualTo(timeScheduleMode.triggerDescription) } @Test @@ -437,7 +439,8 @@ class ModesDialogViewModelTest : SysuiTestCase() { with(tiles?.elementAt(6)!!) { assertThat(this.stateDescription).isEqualTo("Off") assertThat(this.subtextDescription) - .isEqualTo("Monday to Wednesday, 11:00 AM - 3:00 PM") + .isEqualTo(SystemZenRules.getDaysOfWeekFull(context, timeScheduleInfo) + + ", " + SystemZenRules.getTimeSummary(context, timeScheduleInfo)) } // All tiles have the same long click info diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt new file mode 100644 index 000000000000..7a9d0179b239 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt @@ -0,0 +1,70 @@ +/* + * 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.window + +import android.platform.test.annotations.EnableFlags +import android.view.Display.DEFAULT_DISPLAY +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.kosmos.testScope +import com.android.systemui.statusbar.core.StatusBarConnectedDisplays +import com.android.systemui.testKosmos +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.never +import org.mockito.kotlin.verify + +@SmallTest +@RunWith(AndroidJUnit4::class) +@EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) +class MultiDisplayStatusBarWindowControllerStoreTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val fakeDisplayRepository = kosmos.displayRepository + private val testScope = kosmos.testScope + + private val underTest by lazy { kosmos.multiDisplayStatusBarWindowControllerStore } + + @Before + fun start() { + underTest.start() + } + + @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) } + + @Test + fun beforeDisplayRemoved_doesNotStopInstances() = + testScope.runTest { + val instance = underTest.forDisplay(DEFAULT_DISPLAY) + + verify(instance, never()).stop() + } + + @Test + fun displayRemoved_stopsInstance() = + testScope.runTest { + val instance = underTest.forDisplay(DEFAULT_DISPLAY) + + fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY) + + verify(instance).stop() + } +} diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt index 6e66287c1683..61c719319de8 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImplTest.kt @@ -17,12 +17,17 @@ package com.android.systemui.statusbar.window import android.platform.test.annotations.DisableFlags import android.platform.test.annotations.EnableFlags +import android.view.fakeWindowManager import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.concurrency.fakeExecutor +import com.android.systemui.fragments.fragmentService import com.android.systemui.statusbar.core.StatusBarConnectedDisplays +import com.android.systemui.statusbar.core.StatusBarRootModernization import com.android.systemui.statusbar.policy.statusBarConfigurationController import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any @@ -37,6 +42,9 @@ class StatusBarWindowControllerImplTest : SysuiTestCase() { testKosmos().also { it.statusBarWindowViewInflater = it.fakeStatusBarWindowViewInflater } private val underTest = kosmos.statusBarWindowControllerImpl + private val fakeExecutor = kosmos.fakeExecutor + private val fakeWindowManager = kosmos.fakeWindowManager + private val mockFragmentService = kosmos.fragmentService private val fakeStatusBarWindowViewInflater = kosmos.fakeStatusBarWindowViewInflater private val statusBarConfigurationController = kosmos.statusBarConfigurationController @@ -59,4 +67,64 @@ class StatusBarWindowControllerImplTest : SysuiTestCase() { verify(mockWindowView, never()).setStatusBarConfigurationController(any()) } + + @Test + @EnableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarConnectedDisplays.FLAG_NAME) + fun stop_statusBarModernizationFlagEnabled_doesNotRemoveFragment() { + val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first() + + underTest.stop() + fakeExecutor.runAllReady() + + verify(mockFragmentService, never()).removeAndDestroy(windowView) + } + + @Test + @DisableFlags(StatusBarRootModernization.FLAG_NAME) + @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) + fun stop_statusBarModernizationFlagDisabled_removesFragment() { + val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first() + + underTest.stop() + fakeExecutor.runAllReady() + + verify(mockFragmentService).removeAndDestroy(windowView) + } + + @Test + @DisableFlags(StatusBarRootModernization.FLAG_NAME) + @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) + fun stop_statusBarModernizationFlagDisabled_removesFragmentOnExecutor() { + val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first() + + underTest.stop() + + verify(mockFragmentService, never()).removeAndDestroy(windowView) + fakeExecutor.runAllReady() + verify(mockFragmentService).removeAndDestroy(windowView) + } + + @Test + @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME) + fun stop_removesWindowViewFromWindowManager() { + underTest.attach() + underTest.stop() + + assertThat(fakeWindowManager.addedViews).isEmpty() + } + + @Test(expected = IllegalStateException::class) + @DisableFlags(StatusBarConnectedDisplays.FLAG_NAME) + fun stop_connectedDisplaysFlagDisabled_crashes() { + underTest.stop() + } + + @Test + fun attach_windowViewAddedToWindowManager() { + val windowView = fakeStatusBarWindowViewInflater.inflatedMockViews.first() + + underTest.attach() + + assertThat(fakeWindowManager.addedViews.keys).containsExactly(windowView) + } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt index 2e6d0fc847bb..e25bf13c41f2 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/SettingsProxyTest.kt @@ -27,7 +27,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestScope @@ -57,7 +57,7 @@ class SettingsProxyTest : SysuiTestCase() { @Before fun setUp() { testScope = TestScope(testDispatcher) - mSettings = FakeSettingsProxy(testDispatcher) + mSettings = FakeSettingsProxy(testScope) mContentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {} } @@ -92,7 +92,7 @@ class SettingsProxyTest : SysuiTestCase() { mSettings.registerContentObserverSync( TEST_SETTING, notifyForDescendants = true, - mContentObserver + mContentObserver, ) verify(mSettings.getContentResolver()) .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver)) @@ -104,7 +104,7 @@ class SettingsProxyTest : SysuiTestCase() { mSettings.registerContentObserver( TEST_SETTING, notifyForDescendants = true, - mContentObserver + mContentObserver, ) verify(mSettings.getContentResolver()) .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver)) @@ -116,7 +116,7 @@ class SettingsProxyTest : SysuiTestCase() { mSettings.registerContentObserverAsync( TEST_SETTING, notifyForDescendants = true, - mContentObserver + mContentObserver, ) testScope.advanceUntilIdle() verify(mSettings.getContentResolver()) @@ -154,7 +154,7 @@ class SettingsProxyTest : SysuiTestCase() { mSettings.registerContentObserverSync( TEST_SETTING_URI, notifyForDescendants = true, - mContentObserver + mContentObserver, ) verify(mSettings.getContentResolver()) .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver)) @@ -166,7 +166,7 @@ class SettingsProxyTest : SysuiTestCase() { mSettings.registerContentObserver( TEST_SETTING_URI, notifyForDescendants = true, - mContentObserver + mContentObserver, ) verify(mSettings.getContentResolver()) .registerContentObserver(eq(TEST_SETTING_URI), eq(true), eq(mContentObserver)) @@ -178,7 +178,7 @@ class SettingsProxyTest : SysuiTestCase() { mSettings.registerContentObserverAsync( TEST_SETTING_URI, notifyForDescendants = true, - mContentObserver + mContentObserver, ) testScope.advanceUntilIdle() verify(mSettings.getContentResolver()) @@ -202,7 +202,7 @@ class SettingsProxyTest : SysuiTestCase() { TEST_SETTING_URI, false, mContentObserver, - it + it, ) } } @@ -382,15 +382,15 @@ class SettingsProxyTest : SysuiTestCase() { assertThat(mSettings.getFloat(TEST_SETTING, 2.5F)).isEqualTo(2.5F) } - private class FakeSettingsProxy(val testDispatcher: CoroutineDispatcher) : SettingsProxy { + private class FakeSettingsProxy(val testScope: CoroutineScope) : SettingsProxy { private val mContentResolver = mock(ContentResolver::class.java) private val settingToValueMap: MutableMap<String, String?> = mutableMapOf() override fun getContentResolver() = mContentResolver - override val backgroundDispatcher: CoroutineDispatcher - get() = testDispatcher + override val settingsScope: CoroutineScope + get() = testScope override fun getUriFor(name: String) = Uri.parse(StringBuilder().append("content://settings/").append(name).toString()) @@ -408,7 +408,7 @@ class SettingsProxyTest : SysuiTestCase() { name: String, value: String?, tag: String?, - makeDefault: Boolean + makeDefault: Boolean, ): Boolean { settingToValueMap[name] = value return true diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt index 00b8cd04bdaf..5787f7dfc61f 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/util/settings/UserSettingsProxyTest.kt @@ -28,7 +28,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.google.common.truth.Truth.assertThat -import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch import kotlinx.coroutines.test.StandardTestDispatcher @@ -36,7 +36,6 @@ import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Assert.assertThrows -import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.mock @@ -51,14 +50,9 @@ class UserSettingsProxyTest : SysuiTestCase() { private var userId = MAIN_USER_ID private val testDispatcher = StandardTestDispatcher() - private var mSettings: UserSettingsProxy = FakeUserSettingsProxy({ userId }, testDispatcher) + private val testScope = TestScope(testDispatcher) + private var mSettings: UserSettingsProxy = FakeUserSettingsProxy({ userId }, testScope) private var mContentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) {} - private lateinit var testScope: TestScope - - @Before - fun setUp() { - testScope = TestScope(testDispatcher) - } @Test fun registerContentObserverForUser_inputString_success() = @@ -69,7 +63,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -82,7 +76,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -96,7 +90,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -107,14 +101,14 @@ class UserSettingsProxyTest : SysuiTestCase() { TEST_SETTING, notifyForDescendants = true, mContentObserver, - userId + userId, ) verify(mSettings.getContentResolver()) .registerContentObserver( eq(TEST_SETTING_URI), eq(true), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -125,16 +119,14 @@ class UserSettingsProxyTest : SysuiTestCase() { TEST_SETTING, notifyForDescendants = true, mContentObserver, - userId + userId, ) verify(mSettings.getContentResolver()) .registerContentObserver( eq(TEST_SETTING_URI), - eq( - true, - ), + eq(true), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -145,7 +137,7 @@ class UserSettingsProxyTest : SysuiTestCase() { TEST_SETTING, notifyForDescendants = true, mContentObserver, - userId + userId, ) testScope.advanceUntilIdle() verify(mSettings.getContentResolver()) @@ -153,7 +145,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(true), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -166,7 +158,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -179,7 +171,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -189,7 +181,7 @@ class UserSettingsProxyTest : SysuiTestCase() { mSettings.registerContentObserverForUserAsync( TEST_SETTING_URI, mContentObserver, - userId + userId, ) testScope.advanceUntilIdle() @@ -198,7 +190,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -213,7 +205,7 @@ class UserSettingsProxyTest : SysuiTestCase() { TEST_SETTING_URI, mContentObserver, userId, - runnable + runnable, ) testScope.advanceUntilIdle() assertThat(callbackCalled).isTrue() @@ -226,14 +218,14 @@ class UserSettingsProxyTest : SysuiTestCase() { TEST_SETTING_URI, notifyForDescendants = true, mContentObserver, - userId + userId, ) verify(mSettings.getContentResolver()) .registerContentObserver( eq(TEST_SETTING_URI), eq(true), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -244,14 +236,14 @@ class UserSettingsProxyTest : SysuiTestCase() { TEST_SETTING_URI, notifyForDescendants = true, mContentObserver, - userId + userId, ) verify(mSettings.getContentResolver()) .registerContentObserver( eq(TEST_SETTING_URI), eq(true), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -262,7 +254,7 @@ class UserSettingsProxyTest : SysuiTestCase() { TEST_SETTING_URI, notifyForDescendants = true, mContentObserver, - userId + userId, ) testScope.advanceUntilIdle() verify(mSettings.getContentResolver()) @@ -270,7 +262,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(true), eq(mContentObserver), - eq(MAIN_USER_ID) + eq(MAIN_USER_ID), ) } @@ -283,7 +275,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(0) + eq(0), ) } @@ -296,7 +288,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(0) + eq(0), ) } @@ -309,7 +301,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(0) + eq(0), ) } } @@ -320,14 +312,14 @@ class UserSettingsProxyTest : SysuiTestCase() { mSettings.registerContentObserverSync( TEST_SETTING_URI, notifyForDescendants = true, - mContentObserver + mContentObserver, ) verify(mSettings.getContentResolver()) .registerContentObserver( eq(TEST_SETTING_URI), eq(true), eq(mContentObserver), - eq(0) + eq(0), ) } @@ -340,7 +332,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(0) + eq(0), ) } @@ -354,7 +346,7 @@ class UserSettingsProxyTest : SysuiTestCase() { eq(TEST_SETTING_URI), eq(false), eq(mContentObserver), - eq(0) + eq(0), ) } } @@ -557,7 +549,7 @@ class UserSettingsProxyTest : SysuiTestCase() { */ private class FakeUserSettingsProxy( override val currentUserProvider: SettingsProxy.CurrentUserIdProvider, - val testDispatcher: CoroutineDispatcher + val testScope: CoroutineScope, ) : UserSettingsProxy { private val mContentResolver = mock(ContentResolver::class.java) @@ -569,8 +561,8 @@ class UserSettingsProxyTest : SysuiTestCase() { override fun getUriFor(name: String) = Uri.parse(StringBuilder().append(URI_PREFIX).append(name).toString()) - override val backgroundDispatcher: CoroutineDispatcher - get() = testDispatcher + override val settingsScope: CoroutineScope + get() = testScope override fun getStringForUser(name: String, userHandle: Int) = userIdToSettingsValueMap[userHandle]?.get(name) ?: "" @@ -578,7 +570,7 @@ class UserSettingsProxyTest : SysuiTestCase() { override fun putString( name: String, value: String?, - overrideableByRestore: Boolean + overrideableByRestore: Boolean, ): Boolean { userIdToSettingsValueMap[DEFAULT_USER_ID]?.put(name, value) return true @@ -588,7 +580,7 @@ class UserSettingsProxyTest : SysuiTestCase() { name: String, value: String?, tag: String?, - makeDefault: Boolean + makeDefault: Boolean, ): Boolean { putStringForUser(name, value, DEFAULT_USER_ID) return true @@ -605,7 +597,7 @@ class UserSettingsProxyTest : SysuiTestCase() { tag: String?, makeDefault: Boolean, userHandle: Int, - overrideableByRestore: Boolean + overrideableByRestore: Boolean, ): Boolean { userIdToSettingsValueMap[userHandle]?.set(name, value) return true 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 89da46544f1e..fb9e96c820cf 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 @@ -139,7 +139,9 @@ data class ClockMessageBuffers( /** Message buffer for large clock rendering */ val largeClockMessageBuffer: MessageBuffer, -) +) { + constructor(buffer: MessageBuffer) : this(buffer, buffer, buffer) {} +} data class AodClockBurnInModel(val scale: Float, val translationX: Float, val translationY: Float) diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java index d68501f69bc0..6b909529e33a 100644 --- a/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/GlobalSettingsImpl.java @@ -25,7 +25,7 @@ import android.provider.Settings; import com.android.systemui.util.settings.SettingsSingleThreadBackground; -import kotlinx.coroutines.CoroutineDispatcher; +import kotlinx.coroutines.CoroutineScope; import javax.inject.Inject; @@ -33,13 +33,13 @@ import javax.inject.Inject; @SuppressLint("StaticSettingsProvider") class GlobalSettingsImpl implements GlobalSettings { private final ContentResolver mContentResolver; - private final CoroutineDispatcher mBgDispatcher; + private final CoroutineScope mSettingsScope; @Inject GlobalSettingsImpl(ContentResolver contentResolver, - @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) { + @SettingsSingleThreadBackground CoroutineScope settingsScope) { mContentResolver = contentResolver; - mBgDispatcher = bgDispatcher; + mSettingsScope = settingsScope; } @NonNull @@ -56,8 +56,8 @@ class GlobalSettingsImpl implements GlobalSettings { @NonNull @Override - public CoroutineDispatcher getBackgroundDispatcher() { - return mBgDispatcher; + public CoroutineScope getSettingsScope() { + return mSettingsScope; } @Override diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java index 211a6f48e475..ae89a5f021c2 100644 --- a/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SecureSettingsImpl.java @@ -23,23 +23,23 @@ import android.provider.Settings; import com.android.systemui.util.settings.SettingsSingleThreadBackground; -import kotlinx.coroutines.CoroutineDispatcher; +import kotlinx.coroutines.CoroutineScope; import javax.inject.Inject; class SecureSettingsImpl implements SecureSettings { private final ContentResolver mContentResolver; private final CurrentUserIdProvider mCurrentUserProvider; - private final CoroutineDispatcher mBgDispatcher; + private final CoroutineScope mSettingsScope; @Inject SecureSettingsImpl( ContentResolver contentResolver, CurrentUserIdProvider currentUserProvider, - @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) { + @SettingsSingleThreadBackground CoroutineScope settingsScope) { mContentResolver = contentResolver; mCurrentUserProvider = currentUserProvider; - mBgDispatcher = bgDispatcher; + mSettingsScope = settingsScope; } @NonNull @@ -62,8 +62,8 @@ class SecureSettingsImpl implements SecureSettings { @NonNull @Override - public CoroutineDispatcher getBackgroundDispatcher() { - return mBgDispatcher; + public CoroutineScope getSettingsScope() { + return mSettingsScope; } @Override diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt index 5d0b0d55e1f6..154d3cc9eda1 100644 --- a/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SettingsProxy.kt @@ -23,10 +23,12 @@ import android.provider.Settings.SettingNotFoundException import androidx.annotation.AnyThread import androidx.annotation.WorkerThread import com.android.app.tracing.TraceUtils.trace -import com.android.systemui.coroutines.newTracingContext +import com.android.app.tracing.coroutines.launchTraced as launch +import com.android.app.tracing.coroutines.nameCoroutine +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope -import com.android.app.tracing.coroutines.launchTraced as launch import kotlinx.coroutines.withContext /** @@ -47,11 +49,14 @@ interface SettingsProxy { /** Returns the [ContentResolver] this instance was constructed with. */ fun getContentResolver(): ContentResolver - /** - * Returns the background [CoroutineDispatcher] that the async APIs will use for a specific - * implementation. - */ - val backgroundDispatcher: CoroutineDispatcher + /** Returns the [CoroutineScope] that the async APIs will use. */ + val settingsScope: CoroutineScope + + @OptIn(ExperimentalStdlibApi::class) + fun settingsDispatcherContext(name: String): CoroutineContext { + return (settingsScope.coroutineContext[CoroutineDispatcher] ?: EmptyCoroutineContext) + + nameCoroutine(name) + } /** * Construct the content URI for a particular name/value pair, useful for monitoring changes @@ -82,7 +87,7 @@ interface SettingsProxy { * wish to synchronize execution. */ suspend fun registerContentObserver(name: String, settingsObserver: ContentObserver) { - withContext(backgroundDispatcher) { + withContext(settingsDispatcherContext("registerContentObserver-A")) { registerContentObserverSync(getUriFor(name), settingsObserver) } } @@ -94,7 +99,7 @@ interface SettingsProxy { */ @AnyThread fun registerContentObserverAsync(name: String, settingsObserver: ContentObserver) = - CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-A")).launch { + settingsScope.launch("registerContentObserverAsync-A") { registerContentObserverSync(getUriFor(name), settingsObserver) } @@ -111,7 +116,7 @@ interface SettingsProxy { settingsObserver: ContentObserver, @WorkerThread registered: Runnable, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-B")).launch { + settingsScope.launch("registerContentObserverAsync-B") { registerContentObserverSync(getUriFor(name), settingsObserver) registered.run() } @@ -134,7 +139,9 @@ interface SettingsProxy { * wish to synchronize execution. */ suspend fun registerContentObserver(uri: Uri, settingsObserver: ContentObserver) { - withContext(backgroundDispatcher) { registerContentObserverSync(uri, settingsObserver) } + withContext(settingsDispatcherContext("registerContentObserver-B")) { + registerContentObserverSync(uri, settingsObserver) + } } /** @@ -144,7 +151,7 @@ interface SettingsProxy { */ @AnyThread fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) = - CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-C")).launch { + settingsScope.launch("registerContentObserverAsync-C") { registerContentObserverSync(uri, settingsObserver) } @@ -161,7 +168,7 @@ interface SettingsProxy { settingsObserver: ContentObserver, @WorkerThread registered: Runnable, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-D")).launch { + settingsScope.launch("registerContentObserverAsync-D") { registerContentObserverSync(uri, settingsObserver) registered.run() } @@ -188,9 +195,9 @@ interface SettingsProxy { suspend fun registerContentObserver( name: String, notifyForDescendants: Boolean, - settingsObserver: ContentObserver + settingsObserver: ContentObserver, ) { - withContext(backgroundDispatcher) { + withContext(settingsDispatcherContext("registerContentObserver-C")) { registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver) } } @@ -206,7 +213,7 @@ interface SettingsProxy { notifyForDescendants: Boolean, settingsObserver: ContentObserver, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-E")).launch { + settingsScope.launch("registerContentObserverAsync-E") { registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver) } @@ -224,7 +231,7 @@ interface SettingsProxy { settingsObserver: ContentObserver, @WorkerThread registered: Runnable, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-F")).launch { + settingsScope.launch("registerContentObserverAsync-F") { registerContentObserverSync(getUriFor(name), notifyForDescendants, settingsObserver) registered.run() } @@ -239,7 +246,7 @@ interface SettingsProxy { fun registerContentObserverSync( uri: Uri, notifyForDescendants: Boolean, - settingsObserver: ContentObserver + settingsObserver: ContentObserver, ) { trace({ "SP#registerObserver#[$uri]" }) { getContentResolver() @@ -257,9 +264,9 @@ interface SettingsProxy { suspend fun registerContentObserver( uri: Uri, notifyForDescendants: Boolean, - settingsObserver: ContentObserver + settingsObserver: ContentObserver, ) { - withContext(backgroundDispatcher) { + withContext(settingsDispatcherContext("registerContentObserver-D")) { registerContentObserverSync(uri, notifyForDescendants, settingsObserver) } } @@ -275,7 +282,7 @@ interface SettingsProxy { notifyForDescendants: Boolean, settingsObserver: ContentObserver, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-G")).launch { + settingsScope.launch("registerContentObserverAsync-G") { registerContentObserverSync(uri, notifyForDescendants, settingsObserver) } @@ -293,7 +300,7 @@ interface SettingsProxy { settingsObserver: ContentObserver, @WorkerThread registered: Runnable, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-H")).launch { + settingsScope.launch("registerContentObserverAsync-H") { registerContentObserverSync(uri, notifyForDescendants, settingsObserver) registered.run() } @@ -319,7 +326,9 @@ interface SettingsProxy { * async block if they wish to synchronize execution. */ suspend fun unregisterContentObserver(settingsObserver: ContentObserver) { - withContext(backgroundDispatcher) { unregisterContentObserverSync(settingsObserver) } + withContext(settingsDispatcherContext("unregisterContentObserver")) { + unregisterContentObserverSync(settingsObserver) + } } /** @@ -330,7 +339,7 @@ interface SettingsProxy { */ @AnyThread fun unregisterContentObserverAsync(settingsObserver: ContentObserver) = - CoroutineScope(backgroundDispatcher + newTracingContext("SettingsProxy-I")).launch { + settingsScope.launch("unregisterContentObserverAsync") { unregisterContentObserver(settingsObserver) } diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java index 1b3f74e0c983..65d1c276cbfa 100644 --- a/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/SystemSettingsImpl.java @@ -23,22 +23,22 @@ import android.provider.Settings; import com.android.systemui.util.settings.SettingsSingleThreadBackground; -import kotlinx.coroutines.CoroutineDispatcher; +import kotlinx.coroutines.CoroutineScope; import javax.inject.Inject; class SystemSettingsImpl implements SystemSettings { private final ContentResolver mContentResolver; private final CurrentUserIdProvider mCurrentUserProvider; - private final CoroutineDispatcher mBgCoroutineDispatcher; + private final CoroutineScope mSettingsScope; @Inject SystemSettingsImpl(ContentResolver contentResolver, CurrentUserIdProvider currentUserProvider, - @SettingsSingleThreadBackground CoroutineDispatcher bgDispatcher) { + @SettingsSingleThreadBackground CoroutineScope settingsScope) { mContentResolver = contentResolver; mCurrentUserProvider = currentUserProvider; - mBgCoroutineDispatcher = bgDispatcher; + mSettingsScope = settingsScope; } @NonNull @@ -61,8 +61,8 @@ class SystemSettingsImpl implements SystemSettings { @NonNull @Override - public CoroutineDispatcher getBackgroundDispatcher() { - return mBgCoroutineDispatcher; + public CoroutineScope getSettingsScope() { + return mSettingsScope; } @Override diff --git a/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt b/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt index 4b03df6b0070..1a5517059ca4 100644 --- a/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt +++ b/packages/SystemUI/pods/com/android/systemui/util/settings/UserSettingsProxy.kt @@ -23,13 +23,11 @@ import android.net.Uri import android.os.UserHandle import android.provider.Settings.SettingNotFoundException import com.android.app.tracing.TraceUtils.trace -import com.android.systemui.coroutines.newTracingContext +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloat import com.android.systemui.util.settings.SettingsProxy.Companion.parseFloatOrThrow import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrThrow import com.android.systemui.util.settings.SettingsProxy.Companion.parseLongOrUseDefault -import kotlinx.coroutines.CoroutineScope -import com.android.app.tracing.coroutines.launchTraced as launch import kotlinx.coroutines.withContext /** @@ -73,13 +71,13 @@ interface UserSettingsProxy : SettingsProxy { } override suspend fun registerContentObserver(uri: Uri, settingsObserver: ContentObserver) { - withContext(backgroundDispatcher) { + withContext(settingsDispatcherContext("registerContentObserver-A")) { registerContentObserverForUserSync(uri, settingsObserver, userId) } } override fun registerContentObserverAsync(uri: Uri, settingsObserver: ContentObserver) = - CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-A")).launch { + settingsScope.launch("registerContentObserverAsync-A") { registerContentObserverForUserSync(uri, settingsObserver, userId) } @@ -96,9 +94,9 @@ interface UserSettingsProxy : SettingsProxy { override suspend fun registerContentObserver( uri: Uri, notifyForDescendants: Boolean, - settingsObserver: ContentObserver + settingsObserver: ContentObserver, ) { - withContext(backgroundDispatcher) { + withContext(settingsDispatcherContext("registerContentObserver-B")) { registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId) } } @@ -113,7 +111,7 @@ interface UserSettingsProxy : SettingsProxy { notifyForDescendants: Boolean, settingsObserver: ContentObserver, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-B")).launch { + settingsScope.launch("registerContentObserverAsync-B") { registerContentObserverForUserSync(uri, notifyForDescendants, settingsObserver, userId) } @@ -126,7 +124,7 @@ interface UserSettingsProxy : SettingsProxy { fun registerContentObserverForUserSync( name: String, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) { registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle) } @@ -141,9 +139,9 @@ interface UserSettingsProxy : SettingsProxy { suspend fun registerContentObserverForUser( name: String, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) { - withContext(backgroundDispatcher) { + withContext(settingsDispatcherContext("registerContentObserverForUser-A")) { registerContentObserverForUserSync(name, settingsObserver, userHandle) } } @@ -158,7 +156,7 @@ interface UserSettingsProxy : SettingsProxy { settingsObserver: ContentObserver, userHandle: Int, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-C")).launch { + settingsScope.launch("registerContentObserverForUserAsync-A") { registerContentObserverForUserSync(getUriFor(name), settingsObserver, userHandle) } @@ -167,7 +165,7 @@ interface UserSettingsProxy : SettingsProxy { fun registerContentObserverForUserSync( uri: Uri, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) { registerContentObserverForUserSync(uri, false, settingsObserver, userHandle) } @@ -182,9 +180,9 @@ interface UserSettingsProxy : SettingsProxy { suspend fun registerContentObserverForUser( uri: Uri, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) { - withContext(backgroundDispatcher) { + withContext(settingsDispatcherContext("registerContentObserverForUser-B")) { registerContentObserverForUserSync(uri, settingsObserver, userHandle) } } @@ -199,7 +197,7 @@ interface UserSettingsProxy : SettingsProxy { settingsObserver: ContentObserver, userHandle: Int, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-D")).launch { + settingsScope.launch("registerContentObserverForUserAsync-B") { registerContentObserverForUserSync(uri, settingsObserver, userHandle) } @@ -216,7 +214,7 @@ interface UserSettingsProxy : SettingsProxy { userHandle: Int, @WorkerThread registered: Runnable, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-E")).launch { + settingsScope.launch("registerContentObserverForUserAsync-C") { registerContentObserverForUserSync(uri, settingsObserver, userHandle) registered.run() } @@ -231,13 +229,13 @@ interface UserSettingsProxy : SettingsProxy { name: String, notifyForDescendants: Boolean, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) { registerContentObserverForUserSync( getUriFor(name), notifyForDescendants, settingsObserver, - userHandle + userHandle, ) } @@ -252,14 +250,14 @@ interface UserSettingsProxy : SettingsProxy { name: String, notifyForDescendants: Boolean, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) { - withContext(backgroundDispatcher) { + withContext(settingsDispatcherContext("registerContentObserverForUser-C")) { registerContentObserverForUserSync( name, notifyForDescendants, settingsObserver, - userHandle + userHandle, ) } } @@ -275,7 +273,7 @@ interface UserSettingsProxy : SettingsProxy { settingsObserver: ContentObserver, userHandle: Int, ) { - CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-F")).launch { + settingsScope.launch("registerContentObserverForUserAsync-D") { registerContentObserverForUserSync( getUriFor(name), notifyForDescendants, @@ -291,7 +289,7 @@ interface UserSettingsProxy : SettingsProxy { uri: Uri, notifyForDescendants: Boolean, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) { trace({ "USP#registerObserver#[$uri]" }) { getContentResolver() @@ -299,7 +297,7 @@ interface UserSettingsProxy : SettingsProxy { uri, notifyForDescendants, settingsObserver, - getRealUserHandle(userHandle) + getRealUserHandle(userHandle), ) Unit } @@ -316,14 +314,14 @@ interface UserSettingsProxy : SettingsProxy { uri: Uri, notifyForDescendants: Boolean, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) { - withContext(backgroundDispatcher) { + withContext(settingsDispatcherContext("registerContentObserverForUser-D")) { registerContentObserverForUserSync( uri, notifyForDescendants, settingsObserver, - getRealUserHandle(userHandle) + getRealUserHandle(userHandle), ) } } @@ -339,7 +337,7 @@ interface UserSettingsProxy : SettingsProxy { settingsObserver: ContentObserver, userHandle: Int, ) = - CoroutineScope(backgroundDispatcher + newTracingContext("UserSettingsProxy-G")).launch { + settingsScope.launch("registerContentObserverForUserAsync-E") { registerContentObserverForUserSync( uri, notifyForDescendants, @@ -385,7 +383,7 @@ interface UserSettingsProxy : SettingsProxy { tag: String?, makeDefault: Boolean, @UserIdInt userHandle: Int, - overrideableByRestore: Boolean + overrideableByRestore: Boolean, ): Boolean override fun getInt(name: String, default: Int): Int { diff --git a/packages/SystemUI/res/drawable/volume_background_top.xml b/packages/SystemUI/res/drawable/volume_background_top.xml index 75849beeb016..132572a41a36 100644 --- a/packages/SystemUI/res/drawable/volume_background_top.xml +++ b/packages/SystemUI/res/drawable/volume_background_top.xml @@ -17,7 +17,6 @@ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <item> <shape> - <size android:width="@dimen/volume_dialog_width" /> <solid android:color="?androidprv:attr/materialColorSurface" /> <corners android:topLeftRadius="@dimen/volume_dialog_background_corner_radius" android:topRightRadius="@dimen/volume_dialog_background_corner_radius"/> diff --git a/packages/SystemUI/res/drawable/volume_dialog_spacer.xml b/packages/SystemUI/res/drawable/volume_dialog_spacer.xml deleted file mode 100644 index 3c60784cf6b6..000000000000 --- a/packages/SystemUI/res/drawable/volume_dialog_spacer.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?><!-- - 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. ---> - -<shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="rectangle"> - <size - android:width="@dimen/volume_dialog_spacing" - android:height="@dimen/volume_dialog_spacing" /> - <solid android:color="@color/transparent" /> -</shape> diff --git a/packages/SystemUI/res/layout/activity_rear_display_front_screen_on.xml b/packages/SystemUI/res/layout/activity_rear_display_front_screen_on.xml new file mode 100644 index 000000000000..a8d4d2ece07f --- /dev/null +++ b/packages/SystemUI/res/layout/activity_rear_display_front_screen_on.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:gravity="center" + android:paddingStart="@dimen/dialog_side_padding" + android:paddingEnd="@dimen/dialog_side_padding" + android:paddingTop="@dimen/dialog_top_padding" + android:paddingBottom="@dimen/dialog_bottom_padding"> + + <androidx.cardview.widget.CardView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + app:cardElevation="0dp" + app:cardCornerRadius="28dp" + app:cardBackgroundColor="@color/rear_display_overlay_animation_background_color"> + + <com.android.systemui.reardisplay.RearDisplayEducationLottieViewWrapper + android:id="@+id/rear_display_folded_animation" + android:importantForAccessibility="no" + android:layout_width="@dimen/rear_display_animation_width_opened" + android:layout_height="@dimen/rear_display_animation_height_opened" + android:layout_gravity="center" + android:contentDescription="@string/rear_display_accessibility_unfolded_animation" + android:scaleType="fitXY" + app:lottie_rawRes="@raw/rear_display_turnaround" + app:lottie_autoPlay="true" + app:lottie_repeatMode="reverse"/> + </androidx.cardview.widget.CardView> + + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/rear_display_unfolded_front_screen_on" + android:textAppearance="@style/TextAppearance.Dialog.Title" + android:lineSpacingExtra="2sp" + android:translationY="-1.24sp" + android:gravity="center_horizontal" /> + + <!-- Buttons --> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginTop="36dp"> + <Space + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1"/> + <TextView + android:id="@+id/button_cancel" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_weight="0" + android:layout_gravity="start" + android:text="@string/cancel" + style="@style/Widget.Dialog.Button.BorderButton" /> + </LinearLayout> + +</LinearLayout> diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip.xml index d0a1ce8ae629..215e4e457060 100644 --- a/packages/SystemUI/res/layout/ongoing_activity_chip.xml +++ b/packages/SystemUI/res/layout/ongoing_activity_chip.xml @@ -55,9 +55,14 @@ /> <!-- Shows generic text. --> + <!-- Since there's so little room in the status bar chip area, don't ellipsize the text and + instead just fade it out a bit at the end. --> <TextView android:id="@+id/ongoing_activity_chip_text" style="@style/StatusBar.Chip.Text" + android:ellipsize="none" + android:requiresFadingEdge="horizontal" + android:fadingEdgeLength="@dimen/ongoing_activity_chip_text_fading_edge_length" android:visibility="gone" /> diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml b/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml index 7c59aad10c91..71c77a56b6a8 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_footer_redesign.xml @@ -44,13 +44,13 @@ android:layout_height="wrap_content"> <com.android.systemui.statusbar.notification.row.FooterViewButton - android:id="@+id/settings_button" + android:id="@+id/history_button" style="@style/TextAppearance.NotificationFooterButtonRedesign" android:layout_width="wrap_content" android:layout_height="48dp" android:background="@drawable/notif_footer_btn_background" - android:contentDescription="@string/notification_settings_button_description" - android:drawableStart="@drawable/notif_footer_btn_settings" + android:contentDescription="@string/notification_history_button_description" + android:drawableStart="@drawable/notif_footer_btn_history" android:focusable="true" app:layout_constraintStart_toStartOf="parent" /> @@ -64,17 +64,17 @@ android:contentDescription="@string/accessibility_clear_all" android:focusable="true" android:text="@string/clear_all_notifications_text" - app:layout_constraintEnd_toStartOf="@id/history_button" - app:layout_constraintStart_toEndOf="@id/settings_button" /> + app:layout_constraintEnd_toStartOf="@id/settings_button" + app:layout_constraintStart_toEndOf="@id/history_button" /> <com.android.systemui.statusbar.notification.row.FooterViewButton - android:id="@+id/history_button" + android:id="@+id/settings_button" style="@style/TextAppearance.NotificationFooterButtonRedesign" android:layout_width="wrap_content" android:layout_height="48dp" android:background="@drawable/notif_footer_btn_background" - android:contentDescription="@string/notification_history_button_description" - android:drawableStart="@drawable/notif_footer_btn_history" + android:contentDescription="@string/notification_settings_button_description" + android:drawableStart="@drawable/notif_footer_btn_settings" android:focusable="true" app:layout_constraintEnd_toEndOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml index f187ce62ddb2..694357d534fb 100644 --- a/packages/SystemUI/res/layout/volume_dialog.xml +++ b/packages/SystemUI/res/layout/volume_dialog.xml @@ -13,58 +13,70 @@ See the License for the specific language governing permissions and limitations under the License. --> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" +<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/volume_dialog_root" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + app:layoutDescription="@xml/volume_dialog_scene"> - <LinearLayout - android:id="@+id/volume_dialog_container" + <View + android:id="@+id/volume_dialog_background" + android:layout_width="@dimen/volume_dialog_width" + android:layout_height="0dp" + android:layout_marginTop="@dimen/volume_dialog_background_vertical_margin" + android:layout_marginBottom="@dimen/volume_dialog_background_vertical_margin" + android:background="@drawable/volume_dialog_background" + app:layout_constraintBottom_toBottomOf="@id/volume_dialog_settings" + app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container" + app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container" + app:layout_constraintTop_toTopOf="@id/volume_ringer_and_drawer_container" /> + + <include + android:id="@id/volume_ringer_and_drawer_container" + layout="@layout/volume_ringer_drawer" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_gravity="center_vertical|end" - android:divider="@drawable/volume_dialog_floating_sliders_spacer" - android:orientation="horizontal" - android:showDividers="middle|end|beginning"> - - <LinearLayout - android:id="@+id/volume_dialog_floating_sliders_container" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:divider="@drawable/volume_dialog_floating_sliders_spacer" - android:gravity="bottom" - android:orientation="horizontal" - android:paddingBottom="@dimen/volume_dialog_floating_sliders_bottom_padding" - android:showDividers="middle" /> + android:layout_marginBottom="@dimen/volume_dialog_components_spacing" + app:layout_constraintBottom_toTopOf="@id/volume_dialog_main_slider_container" + app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container" + app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="1" /> - <LinearLayout - android:id="@+id/volume_dialog" - android:layout_width="@dimen/volume_dialog_width" - android:layout_height="wrap_content" - android:background="@drawable/volume_dialog_background" - android:clipChildren="false" - android:clipToOutline="false" - android:clipToPadding="false" - android:divider="@drawable/volume_dialog_spacer" - android:gravity="center_horizontal" - android:orientation="vertical" - android:paddingVertical="@dimen/volume_dialog_vertical_padding" - android:showDividers="middle"> + <include + android:id="@+id/volume_dialog_main_slider_container" + layout="@layout/volume_dialog_slider" /> - <include layout="@layout/volume_ringer_drawer" /> + <ImageButton + android:id="@+id/volume_dialog_settings" + android:layout_width="@dimen/volume_dialog_button_size" + android:layout_height="@dimen/volume_dialog_button_size" + android:layout_marginTop="@dimen/volume_dialog_components_spacing" + android:background="@drawable/ripple_drawable_20dp" + android:contentDescription="@string/accessibility_volume_settings" + android:soundEffectsEnabled="false" + android:src="@drawable/horizontal_ellipsis" + android:tint="?androidprv:attr/materialColorPrimary" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container" + app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container" + app:layout_constraintTop_toBottomOf="@id/volume_dialog_main_slider_container" + app:layout_constraintVertical_bias="0" /> - <include layout="@layout/volume_dialog_slider" /> + <LinearLayout + android:id="@+id/volume_dialog_floating_sliders_container" + android:layout_width="wrap_content" + android:layout_height="0dp" + android:layout_marginTop="@dimen/volume_dialog_floating_sliders_vertical_padding_negative" + android:layout_marginBottom="@dimen/volume_dialog_floating_sliders_vertical_padding_negative" + android:divider="@drawable/volume_dialog_floating_sliders_spacer" + android:gravity="bottom" + android:orientation="horizontal" + android:showDividers="middle|beginning|end" + app:layout_constraintBottom_toBottomOf="@id/volume_dialog_main_slider_container" + app:layout_constraintEnd_toStartOf="@id/volume_dialog_background" + app:layout_constraintTop_toTopOf="@id/volume_dialog_main_slider_container" /> - <ImageButton - android:id="@+id/volume_dialog_settings" - android:layout_width="@dimen/volume_dialog_button_size" - android:layout_height="@dimen/volume_dialog_button_size" - android:background="@drawable/ripple_drawable_20dp" - android:contentDescription="@string/accessibility_volume_settings" - android:soundEffectsEnabled="false" - android:src="@drawable/horizontal_ellipsis" - android:tint="?androidprv:attr/materialColorPrimary" /> - </LinearLayout> - </LinearLayout> -</FrameLayout>
\ No newline at end of file +</androidx.constraintlayout.motion.widget.MotionLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/volume_ringer_drawer.xml b/packages/SystemUI/res/layout/volume_ringer_drawer.xml index 7c266e60b503..b71c4700c0fa 100644 --- a/packages/SystemUI/res/layout/volume_ringer_drawer.xml +++ b/packages/SystemUI/res/layout/volume_ringer_drawer.xml @@ -19,13 +19,10 @@ android:id="@+id/volume_ringer_and_drawer_container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="center" - android:paddingLeft="@dimen/volume_dialog_ringer_horizontal_padding" - android:paddingRight="@dimen/volume_dialog_ringer_horizontal_padding" - android:layoutDirection="ltr" - android:clipToPadding="false" android:clipChildren="false" - android:background="@drawable/volume_background_top"> + android:clipToPadding="false" + android:gravity="center" + android:layoutDirection="ltr"> <!-- Drawer view, invisible by default. --> <FrameLayout @@ -37,10 +34,10 @@ <!-- View that is animated to a tapped ringer selection, so it appears selected. --> <FrameLayout android:id="@+id/volume_drawer_selection_background" - android:alpha="0.0" android:layout_width="@dimen/volume_dialog_ringer_drawer_button_size" android:layout_height="@dimen/volume_dialog_ringer_drawer_button_size" android:layout_gravity="bottom|right" + android:alpha="0.0" android:background="@drawable/volume_drawer_selection_bg" /> <LinearLayout @@ -65,7 +62,6 @@ android:background="@drawable/volume_drawer_selection_bg" android:contentDescription="@string/volume_ringer_change" android:gravity="center" - android:padding="@dimen/volume_dialog_ringer_horizontal_padding" android:src="@drawable/ic_volume_media" android:tint="?androidprv:attr/materialColorOnPrimary" /> diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml index 4a53df9c2f29..75bee9f9266a 100644 --- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml @@ -46,8 +46,6 @@ <dimen name="lockscreen_shade_max_over_scroll_amount">32dp</dimen> - <dimen name="status_view_margin_horizontal">8dp</dimen> - <!-- Lockscreen shade transition values --> <dimen name="lockscreen_shade_transition_by_tap_distance">200dp</dimen> <dimen name="lockscreen_shade_full_transition_distance">200dp</dimen> diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/packages/SystemUI/res/values-sw600dp-port/dimens.xml index 707bc9e535ff..f73e91af8aff 100644 --- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-port/dimens.xml @@ -16,8 +16,6 @@ --> <resources> <dimen name="notification_panel_margin_horizontal">48dp</dimen> - <dimen name="status_view_margin_horizontal">62dp</dimen> - <!-- qs_tiles_page_horizontal_margin should be margin / 2, otherwise full space between two pages is margin * 2, and that makes tiles page not appear immediately after user swipes to the side --> diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml index 8583f0549960..41bb37efa623 100644 --- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml @@ -22,8 +22,6 @@ <dimen name="keyguard_split_shade_top_margin">72dp</dimen> - <dimen name="status_view_margin_horizontal">24dp</dimen> - <dimen name="qs_media_session_height_expanded">184dp</dimen> <dimen name="qs_content_horizontal_padding">40dp</dimen> <dimen name="qs_horizontal_margin">40dp</dimen> diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml index 9248d585bba7..eb570b8f76d6 100644 --- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml +++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml @@ -20,8 +20,6 @@ <!-- These resources are around just to allow their values to be customized for different hardware and product builds. --> <resources> - <dimen name="status_view_margin_horizontal">124dp</dimen> - <dimen name="large_screen_shade_header_left_padding">24dp</dimen> <dimen name="qqs_layout_padding_bottom">40dp</dimen> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 7af005721e13..b0ae1e2aa53d 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1749,6 +1749,7 @@ <dimen name="ongoing_activity_chip_icon_text_padding">4dp</dimen> <!-- The end padding for the timer text view. Only used if an embedded padding icon is used. --> <dimen name="ongoing_activity_chip_text_end_padding_for_embedded_padding_icon">6dp</dimen> + <dimen name="ongoing_activity_chip_text_fading_edge_length">12dp</dimen> <dimen name="ongoing_activity_chip_corner_radius">28dp</dimen> <!-- Status bar user chip --> @@ -1955,8 +1956,6 @@ <dimen name="dream_overlay_entry_y_offset">40dp</dimen> <dimen name="dream_overlay_exit_y_offset">40dp</dimen> - <dimen name="status_view_margin_horizontal">0dp</dimen> - <!-- Media output broadcast dialog QR code picture size --> <dimen name="media_output_qrcode_size">216dp</dimen> <dimen name="media_output_broadcast_info">21dp</dimen> @@ -2060,26 +2059,29 @@ <dimen name="contextual_edu_dialog_elevation">2dp</dimen> <!-- Volume start --> - <dimen name="volume_dialog_background_corner_radius">30dp</dimen> <dimen name="volume_dialog_width">60dp</dimen> - <dimen name="volume_dialog_vertical_padding">10dp</dimen> + + <dimen name="volume_dialog_background_corner_radius">30dp</dimen> + <dimen name="volume_dialog_background_vertical_margin">-10dp</dimen> + <dimen name="volume_dialog_components_spacing">8dp</dimen> <dimen name="volume_dialog_floating_sliders_spacing">8dp</dimen> <dimen name="volume_dialog_floating_sliders_vertical_padding">10dp</dimen> + <dimen name="volume_dialog_floating_sliders_vertical_padding_negative">-10dp</dimen> <dimen name="volume_dialog_floating_sliders_horizontal_padding">4dp</dimen> - <dimen name="volume_dialog_spacing">4dp</dimen> <dimen name="volume_dialog_button_size">48dp</dimen> - <dimen name="volume_dialog_floating_sliders_bottom_padding">48dp</dimen> <dimen name="volume_dialog_slider_width">52dp</dimen> <dimen name="volume_dialog_slider_height">254dp</dimen> - <dimen name="volume_panel_slice_vertical_padding">8dp</dimen> - <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen> + <fraction name="volume_dialog_half_opened_bias">0.2</fraction> + + <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen> - <dimen name="volume_dialog_ringer_horizontal_padding">10dp</dimen> <dimen name="volume_dialog_ringer_drawer_button_size">40dp</dimen> <dimen name="volume_dialog_ringer_drawer_button_icon_radius">10dp</dimen> - <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen> <dimen name="volume_dialog_ringer_selected_button_background_radius">20dp</dimen> + + <dimen name="volume_panel_slice_vertical_padding">8dp</dimen> + <dimen name="volume_panel_slice_horizontal_padding">24dp</dimen> <!-- Volume end --> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index b45aaddef183..245ba0aca876 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -3568,6 +3568,8 @@ <string name="rear_display_accessibility_folded_animation">Foldable device being unfolded</string> <!-- Text for education page content description for unfolded animation. [CHAR_LIMIT=NONE] --> <string name="rear_display_accessibility_unfolded_animation">Foldable device being flipped around</string> + <!-- Text for a dialog telling the user that the front screen is turned on. [CHAR_LIMIT=NONE] --> + <string name="rear_display_unfolded_front_screen_on">Front screen turned on</string> <!-- QuickSettings: Additional label for the auto-rotation quicksettings tile indicating that the setting corresponds to the folded posture for a foldable device [CHAR LIMIT=32] --> <string name="quick_settings_rotation_posture_folded">folded</string> diff --git a/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml new file mode 100644 index 000000000000..9018e5b7ed92 --- /dev/null +++ b/packages/SystemUI/res/xml/volume_dialog_constraint_set.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/volume_dialog_constraint_set"> + + <Constraint + android:id="@id/volume_dialog_main_slider_container" + android:layout_width="@dimen/volume_dialog_slider_width" + android:layout_height="@dimen/volume_dialog_slider_height" + android:layout_marginEnd="@dimen/volume_dialog_components_spacing" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.5" /> +</ConstraintSet>
\ No newline at end of file diff --git a/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml new file mode 100644 index 000000000000..297c38873164 --- /dev/null +++ b/packages/SystemUI/res/xml/volume_dialog_half_folded_constraint_set.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<ConstraintSet xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/volume_dialog_half_folded_constraint_set"> + + <Constraint + android:id="@id/volume_dialog_main_slider_container" + android:layout_width="@dimen/volume_dialog_slider_width" + android:layout_height="@dimen/volume_dialog_slider_height" + android:layout_marginEnd="@dimen/volume_dialog_components_spacing" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="@fraction/volume_dialog_half_opened_bias" /> +</ConstraintSet>
\ No newline at end of file diff --git a/packages/SystemUI/res/xml/volume_dialog_scene.xml b/packages/SystemUI/res/xml/volume_dialog_scene.xml new file mode 100644 index 000000000000..b813474490bb --- /dev/null +++ b/packages/SystemUI/res/xml/volume_dialog_scene.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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. + --> + +<MotionScene xmlns:motion="http://schemas.android.com/apk/res-auto"> + + <Transition + motion:autoTransition="none" + motion:constraintSetEnd="@id/volume_dialog_half_folded_constraint_set" + motion:constraintSetStart="@id/volume_dialog_constraint_set" + motion:duration="150" /> + + <Include motion:constraintSet="@xml/volume_dialog_constraint_set" /> + <Include motion:constraintSet="@xml/volume_dialog_half_folded_constraint_set" /> +</MotionScene>
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 95830b5f4ed7..add459b84ac1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -44,7 +44,7 @@ import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.navigationbar.NavigationBarController; import com.android.systemui.navigationbar.views.NavigationBarView; import com.android.systemui.settings.DisplayTracker; -import com.android.systemui.shade.data.repository.ShadePositionRepository; +import com.android.systemui.shade.data.repository.ShadeDisplaysRepository; import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -66,7 +66,7 @@ public class KeyguardDisplayManager { private final DisplayManager mDisplayService; private final DisplayTracker mDisplayTracker; private final Lazy<NavigationBarController> mNavigationBarControllerLazy; - private final Provider<ShadePositionRepository> mShadePositionRepositoryProvider; + private final Provider<ShadeDisplaysRepository> mShadePositionRepositoryProvider; private final ConnectedDisplayKeyguardPresentation.Factory mConnectedDisplayKeyguardPresentationFactory; private final Context mContext; @@ -112,7 +112,7 @@ public class KeyguardDisplayManager { KeyguardStateController keyguardStateController, ConnectedDisplayKeyguardPresentation.Factory connectedDisplayKeyguardPresentationFactory, - Provider<ShadePositionRepository> shadePositionRepositoryProvider, + Provider<ShadeDisplaysRepository> shadePositionRepositoryProvider, @Application CoroutineScope appScope) { mContext = context; mNavigationBarControllerLazy = navigationBarControllerLazy; diff --git a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java index fb00d6e16dcc..db4d613a9101 100644 --- a/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/ambient/touch/TouchMonitor.java @@ -52,6 +52,8 @@ import com.android.systemui.util.display.DisplayHelper; import com.google.common.util.concurrent.ListenableFuture; +import kotlin.Unit; + import kotlinx.coroutines.Job; import java.util.Collection; @@ -87,7 +89,7 @@ public class TouchMonitor { private final ConfigurationInteractor mConfigurationInteractor; private final Lifecycle mLifecycle; - private Rect mExclusionRect = null; + private Rect mExclusionRect = new Rect(); private ISystemGestureExclusionListener mGestureExclusionListener; @@ -298,9 +300,18 @@ public class TouchMonitor { public void onSystemGestureExclusionChanged(int displayId, Region systemGestureExclusion, Region systemGestureExclusionUnrestricted) { - mExclusionRect = systemGestureExclusion.getBounds(); + final Rect bounds = systemGestureExclusion.getBounds(); + if (!mExclusionRect.equals(bounds)) { + mExclusionRect = bounds; + mLogger.i(msg -> "Exclusion rect updated to " + msg.getStr1(), + msg -> { + msg.setStr1(bounds.toString()); + return Unit.INSTANCE; + }); + } } }; + mLogger.i("Registering system gesture exclusion listener"); mWindowManagerService.registerSystemGestureExclusionListener( mGestureExclusionListener, mDisplayId); } catch (RemoteException e) { @@ -320,11 +331,12 @@ public class TouchMonitor { * Destroys any active {@link InputSession}. */ private void stopMonitoring(boolean force) { - mExclusionRect = null; + mExclusionRect = new Rect(); if (bouncerAreaExclusion()) { mBackgroundExecutor.execute(() -> { try { if (mGestureExclusionListener != null) { + mLogger.i("Unregistering system gesture exclusion listener"); mWindowManagerService.unregisterSystemGestureExclusionListener( mGestureExclusionListener, mDisplayId); mGestureExclusionListener = null; diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt index 4e0e11226faa..5ecf2e6b2551 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt @@ -29,6 +29,7 @@ import com.android.systemui.communal.domain.model.CommunalContentModel import com.android.systemui.communal.shared.model.EditModeState import com.android.systemui.communal.widgets.WidgetConfigurator import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf import com.android.systemui.util.kotlin.BooleanFlowOperators.not @@ -43,6 +44,7 @@ abstract class BaseCommunalViewModel( val communalSceneInteractor: CommunalSceneInteractor, private val communalInteractor: CommunalInteractor, val mediaHost: MediaHost, + val mediaCarouselController: MediaCarouselController, ) { val currentScene: Flow<SceneKey> = communalSceneInteractor.currentScene diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt index ccff23003aa0..736ed5c7d336 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt @@ -46,6 +46,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger import com.android.systemui.log.dagger.CommunalLog +import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.dagger.MediaModule import com.android.systemui.res.R @@ -82,7 +83,14 @@ constructor( private val accessibilityManager: AccessibilityManager, private val packageManager: PackageManager, @Named(LAUNCHER_PACKAGE) private val launcherPackage: String, -) : BaseCommunalViewModel(communalSceneInteractor, communalInteractor, mediaHost) { + mediaCarouselController: MediaCarouselController, +) : + BaseCommunalViewModel( + communalSceneInteractor, + communalInteractor, + mediaHost, + mediaCarouselController, + ) { private val logger = Logger(logBuffer, "CommunalEditModeViewModel") diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt index 623937305921..34962305ff2a 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalTransitionViewModel.kt @@ -31,6 +31,7 @@ import com.android.systemui.keyguard.ui.viewmodel.DreamingToGlanceableHubTransit import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToDreamingTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.GlanceableHubToLockscreenTransitionViewModel import com.android.systemui.keyguard.ui.viewmodel.LockscreenToGlanceableHubTransitionViewModel +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf @@ -41,6 +42,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.merge import kotlinx.coroutines.flow.onStart @@ -60,7 +62,7 @@ constructor( glanceableHubToDreamTransitionViewModel: GlanceableHubToDreamingTransitionViewModel, communalInteractor: CommunalInteractor, private val communalSceneInteractor: CommunalSceneInteractor, - keyguardTransitionInteractor: KeyguardTransitionInteractor + keyguardTransitionInteractor: KeyguardTransitionInteractor, ) { /** * Snaps to [CommunalScenes.Communal], showing the glanceable hub immediately without any @@ -89,7 +91,7 @@ constructor( keyguardTransitionInteractor .transition( edge = Edge.create(from = Scenes.Communal), - edgeWithoutSceneContainer = Edge.create(from = KeyguardState.GLANCEABLE_HUB) + edgeWithoutSceneContainer = Edge.create(from = KeyguardState.GLANCEABLE_HUB), ) .filter { it.to == KeyguardState.OCCLUDED && @@ -114,21 +116,24 @@ constructor( // from // the hub, then pressing power twice to go back to the lock screen. communalSceneInteractor.isCommunalVisible, - merge( - lockscreenToGlanceableHubTransitionViewModel.showUmo, - glanceableHubToLockscreenTransitionViewModel.showUmo, - dreamToGlanceableHubTransitionViewModel.showUmo, - glanceableHubToDreamTransitionViewModel.showUmo, - showUmoFromOccludedToGlanceableHub, - showUmoFromGlanceableHubToOccluded, - ) - .onStart { emit(false) } - ) + // TODO(b/378942852): polish UMO transitions when scene container is enabled + if (SceneContainerFlag.isEnabled) flowOf(true) + else + merge( + lockscreenToGlanceableHubTransitionViewModel.showUmo, + glanceableHubToLockscreenTransitionViewModel.showUmo, + dreamToGlanceableHubTransitionViewModel.showUmo, + glanceableHubToDreamTransitionViewModel.showUmo, + showUmoFromOccludedToGlanceableHub, + showUmoFromGlanceableHubToOccluded, + ) + .onStart { emit(false) }, + ), ) .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), - initialValue = false + initialValue = false, ) /** Whether to show communal when exiting the occluded state. */ @@ -145,8 +150,7 @@ constructor( val recentsBackgroundColor: Flow<Color?> = combine(showCommunalFromOccluded, communalColors.backgroundColor) { showCommunalFromOccluded, - backgroundColor, - -> + backgroundColor -> if (showCommunalFromOccluded) { backgroundColor } else { 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 7990450f6ac8..9cd6465266d4 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 @@ -21,6 +21,7 @@ import android.content.res.Resources import android.os.Bundle import android.view.View import android.view.accessibility.AccessibilityNodeInfo +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.systemui.communal.domain.interactor.CommunalInteractor import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor import com.android.systemui.communal.domain.interactor.CommunalSettingsInteractor @@ -38,6 +39,7 @@ import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.log.LogBuffer import com.android.systemui.log.core.Logger import com.android.systemui.log.dagger.CommunalLog +import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.controls.ui.view.MediaHostState @@ -72,7 +74,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn -import com.android.app.tracing.coroutines.launchTraced as launch /** The default view model used for showing the communal hub. */ @OptIn(ExperimentalCoroutinesApi::class) @@ -95,7 +96,14 @@ constructor( @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost, @CommunalLog logBuffer: LogBuffer, private val metricsLogger: CommunalMetricsLogger, -) : BaseCommunalViewModel(communalSceneInteractor, communalInteractor, mediaHost) { + mediaCarouselController: MediaCarouselController, +) : + BaseCommunalViewModel( + communalSceneInteractor, + communalInteractor, + mediaHost, + mediaCarouselController, + ) { private val logger = Logger(logBuffer, "CommunalViewModel") diff --git a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt index b74ca035a229..35eed5e6a6d9 100644 --- a/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/deviceentry/domain/interactor/DeviceUnlockedInteractor.kt @@ -35,6 +35,7 @@ import com.android.systemui.keyguard.domain.interactor.TrustInteractor import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.power.domain.interactor.PowerInteractor import com.android.systemui.power.shared.model.WakeSleepReason +import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.util.settings.repository.UserAwareSecureSettingsRepository import com.android.systemui.utils.coroutines.flow.flatMapLatestConflated import javax.inject.Inject @@ -363,6 +364,9 @@ constructor( private val interactor: DeviceUnlockedInteractor, ) : CoreStartable { override fun start() { + if (!SceneContainerFlag.isEnabled) + return + applicationScope.launch { interactor.activate() } } } diff --git a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt index 589dbf92de38..e862525623fe 100644 --- a/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt +++ b/packages/SystemUI/src/com/android/systemui/display/DisplayModule.kt @@ -30,6 +30,8 @@ import com.android.systemui.display.data.repository.FocusedDisplayRepository import com.android.systemui.display.data.repository.FocusedDisplayRepositoryImpl import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractorImpl +import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor +import com.android.systemui.display.domain.interactor.RearDisplayStateInteractorImpl import com.android.systemui.statusbar.core.StatusBarConnectedDisplays import dagger.Binds import dagger.Lazy @@ -46,6 +48,11 @@ interface DisplayModule { provider: ConnectedDisplayInteractorImpl ): ConnectedDisplayInteractor + @Binds + fun bindRearDisplayStateInteractor( + provider: RearDisplayStateInteractorImpl + ): RearDisplayStateInteractor + @Binds fun bindsDisplayRepository(displayRepository: DisplayRepositoryImpl): DisplayRepository @Binds diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt index 1da5351ac2a3..29044d017d2d 100644 --- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DeviceStateRepository.kt @@ -20,6 +20,7 @@ import android.content.Context import android.hardware.devicestate.DeviceState as PlatformDeviceState import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY +import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN @@ -49,6 +50,15 @@ interface DeviceStateRepository { UNFOLDED, /** Device state that corresponds to the device being in rear display mode */ REAR_DISPLAY, + /** + * Device state that corresponds to the device being in rear display mode with the inner + * display showing a system-provided affordance to cancel the mode. + * + * TODO(b/371095273): This state will be removed after the RDM_V2 flag lifecycle is complete + * at which point the REAR_DISPLAY state will be the will be the new and only rear display + * mode. + */ + REAR_DISPLAY_OUTER_DEFAULT, /** Device state in that corresponds to the device being in concurrent display mode */ CONCURRENT_DISPLAY, /** Device state in none of the other arrays. */ @@ -62,7 +72,7 @@ constructor( val context: Context, val deviceStateManager: DeviceStateManager, @Background bgScope: CoroutineScope, - @Background executor: Executor + @Background executor: Executor, ) : DeviceStateRepository { override val state: StateFlow<DeviceState> = @@ -105,6 +115,12 @@ constructor( */ private fun PlatformDeviceState.toDeviceStateEnum(): DeviceState { return when { + hasProperties( + PROPERTY_FEATURE_REAR_DISPLAY, + PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT, + ) -> { + DeviceState.REAR_DISPLAY_OUTER_DEFAULT + } hasProperty(PROPERTY_FEATURE_REAR_DISPLAY) -> DeviceState.REAR_DISPLAY hasProperty(PROPERTY_FEATURE_DUAL_DISPLAY_INTERNAL_DEFAULT) -> { DeviceState.CONCURRENT_DISPLAY @@ -112,7 +128,7 @@ constructor( hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY) -> DeviceState.FOLDED hasProperties( PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, - PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN + PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_HALF_OPEN, ) -> DeviceState.HALF_FOLDED hasProperty(PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY) -> { DeviceState.UNFOLDED diff --git a/packages/SystemUI/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractor.kt b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractor.kt new file mode 100644 index 000000000000..b743377881bf --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/display/domain/interactor/RearDisplayStateInteractor.kt @@ -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.systemui.display.domain.interactor + +import android.view.Display +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Background +import com.android.systemui.display.data.repository.DeviceStateRepository +import com.android.systemui.display.data.repository.DisplayRepository +import javax.inject.Inject +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combineTransform +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flowOn + +/** Provides information about the status of Rear Display Mode. */ +interface RearDisplayStateInteractor { + + /** A flow notifying the subscriber of Rear Display state changes */ + val state: Flow<State> + + sealed class State { + /** Indicates that the rear display is disabled */ + data object Disabled : State() + + /** + * Indicates that the device is in Rear Display Mode, and that the inner display is ready to + * show a system-provided affordance allowing the user to cancel out of the Rear Display + * Mode. + */ + data class Enabled(val innerDisplay: Display) : State() + } +} + +@SysUISingleton +class RearDisplayStateInteractorImpl +@Inject +constructor( + displayRepository: DisplayRepository, + deviceStateRepository: DeviceStateRepository, + @Background backgroundCoroutineDispatcher: CoroutineDispatcher, +) : RearDisplayStateInteractor { + + override val state: Flow<RearDisplayStateInteractor.State> = + deviceStateRepository.state + .combineTransform(displayRepository.displays) { state, displays -> + val innerDisplay = displays.find { it.flags and Display.FLAG_REAR != 0 } + + if (state != DeviceStateRepository.DeviceState.REAR_DISPLAY_OUTER_DEFAULT) { + emit(RearDisplayStateInteractor.State.Disabled) + } else if (innerDisplay != null) { + emit(RearDisplayStateInteractor.State.Enabled(innerDisplay)) + } + } + .distinctUntilChanged() + .flowOn(backgroundCoroutineDispatcher) +} diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java index 89fce4a70c6c..abc810afca98 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java @@ -469,9 +469,8 @@ public class DozeScreenBrightness extends BroadcastReceiver implements DozeMachi || posture >= mLightSensorOptional.length) { return; } - - final Sensor oldSensor = mLightSensorOptional[mDevicePosture].get(); - final Sensor newSensor = mLightSensorOptional[posture].get(); + Sensor oldSensor = mLightSensorOptional[mDevicePosture].orElse(null); + Sensor newSensor = mLightSensorOptional[posture].orElse(null); if (Objects.equals(oldSensor, newSensor)) { mDevicePosture = posture; // uses the same sensor for the new posture diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index 1ffbbd2a9f32..b330ba376810 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -65,6 +65,9 @@ import com.android.systemui.dreams.dagger.DreamOverlayComponent; import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; import com.android.systemui.navigationbar.gestural.domain.GestureInteractor; import com.android.systemui.navigationbar.gestural.domain.TaskMatcher; +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.shade.ShadeExpansionChangeEvent; import com.android.systemui.touch.TouchInsetManager; import com.android.systemui.util.concurrency.DelayableExecutor; @@ -162,6 +165,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ private TouchMonitor mTouchMonitor; + private final SceneInteractor mSceneInteractor; private final CommunalInteractor mCommunalInteractor; private boolean mCommunalAvailable; @@ -378,6 +382,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ KeyguardUpdateMonitor keyguardUpdateMonitor, ScrimManager scrimManager, CommunalInteractor communalInteractor, + SceneInteractor sceneInteractor, SystemDialogsCloser systemDialogsCloser, UiEventLogger uiEventLogger, @Named(DREAM_TOUCH_INSET_MANAGER) TouchInsetManager touchInsetManager, @@ -405,6 +410,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ mDreamOverlayCallbackController = dreamOverlayCallbackController; mWindowTitle = windowTitle; mCommunalInteractor = communalInteractor; + mSceneInteractor = sceneInteractor; mSystemDialogsCloser = systemDialogsCloser; mGestureInteractor = gestureInteractor; mDreamOverlayComponentFactory = dreamOverlayComponentFactory; @@ -551,9 +557,15 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ @Override public void onWakeRequested() { mUiEventLogger.log(CommunalUiEvent.DREAM_TO_COMMUNAL_HUB_DREAM_AWAKE_START); - mCommunalInteractor.changeScene(CommunalScenes.Communal, - "dream wake requested", - null); + if (SceneContainerFlag.isEnabled()) { + // Scene interactor can only be modified on main thread. + mExecutor.execute(() -> mSceneInteractor.changeScene(Scenes.Communal, + "dream wake redirect to communal")); + } else { + mCommunalInteractor.changeScene(CommunalScenes.Communal, + "dream wake requested", + null); + } } private void updateGestureBlockingLocked() { @@ -617,7 +629,13 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ mSystemDialogsCloser.closeSystemDialogs(); // Hide glanceable hub (this is a nop if glanceable hub is not open). - mCommunalInteractor.changeScene(CommunalScenes.Blank, "dream come to front", null); + if (SceneContainerFlag.isEnabled()) { + // Scene interactor can only be modified on main thread. + mExecutor.execute( + () -> mSceneInteractor.changeScene(Scenes.Dream, "closing hub to go to dream")); + } else { + mCommunalInteractor.changeScene(CommunalScenes.Blank, "dream come to front", null); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt index b8ac0d282229..5a9e52ae5655 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/dreams/ui/viewmodel/DreamUserActionsViewModel.kt @@ -54,6 +54,8 @@ constructor( shadeInteractor.shadeMode, ) { isDeviceUnlocked, shadeMode -> buildList { + add(Swipe.Start to Scenes.Communal) + val bouncerOrGone = if (isDeviceUnlocked) Scenes.Gone else Scenes.Bouncer add(Swipe.Up to bouncerOrGone) diff --git a/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt b/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt index ed7d1823648a..316964a47753 100644 --- a/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/haptics/msdl/qs/TileHapticsViewModel.kt @@ -83,9 +83,6 @@ constructor( interactionState == TileInteractionState.LONG_CLICKED && animationState == TileAnimationState.ACTIVITY_LAUNCH -> TileHapticsState.LONG_PRESS - interactionState == TileInteractionState.LONG_CLICKED && - !tileViewModel.currentState.handlesLongClick -> - TileHapticsState.FAILED_LONGPRESS else -> TileHapticsState.NO_HAPTICS } } @@ -102,7 +99,6 @@ constructor( TileHapticsState.TOGGLE_ON -> MSDLToken.SWITCH_ON TileHapticsState.TOGGLE_OFF -> MSDLToken.SWITCH_OFF TileHapticsState.LONG_PRESS -> MSDLToken.LONG_PRESS - TileHapticsState.FAILED_LONGPRESS -> MSDLToken.FAILURE TileHapticsState.NO_HAPTICS -> null } tokenToPlay?.let { @@ -154,7 +150,6 @@ constructor( TOGGLE_ON, TOGGLE_OFF, LONG_PRESS, - FAILED_LONGPRESS, NO_HAPTICS, } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt index 41e69297f7c6..3666de460d91 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelper.kt @@ -72,6 +72,7 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -90,6 +91,7 @@ import androidx.compose.ui.input.key.Key import androidx.compose.ui.input.key.key import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -99,6 +101,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.withStyle +import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -377,15 +380,19 @@ private fun ShortcutHelperTwoPane( Column(modifier = modifier.fillMaxSize().padding(horizontal = 24.dp)) { Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { - Box(modifier = Modifier.padding(start = 202.dp).width(412.dp)) { - TitleBar(isCustomizing) - } - Spacer(modifier = Modifier.weight(1f)) - if (isShortcutCustomizerFlagEnabled) { - if (isCustomizing) { - DoneButton(onClick = { isCustomizing = false }) + // Keep title centered whether customize button is visible or not. + Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) { + Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { + TitleBar(isCustomizing) + } + if (isShortcutCustomizerFlagEnabled) { + if (isCustomizing) { + DoneButton(onClick = { isCustomizing = false }) + } else { + CustomizeButton(onClick = { isCustomizing = true }) + } } else { - CustomizeButton(onClick = { isCustomizing = true }) + Spacer(modifier = Modifier.width(if (isCustomizing) 69.dp else 133.dp)) } } } @@ -550,7 +557,7 @@ private fun Shortcut( .padding(8.dp) ) { Row( - modifier = Modifier.width(128.dp).align(Alignment.CenterVertically), + modifier = Modifier.width(128.dp).align(Alignment.CenterVertically).weight(0.333f), horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically, ) { @@ -561,7 +568,7 @@ private fun Shortcut( } Spacer(modifier = Modifier.width(24.dp)) ShortcutKeyCombinations( - modifier = Modifier.weight(1f), + modifier = Modifier.weight(.666f), shortcut = shortcut, isCustomizing = isCustomizing, onAddShortcutRequested = { onCustomizationRequested(shortcut.label) }, @@ -791,16 +798,25 @@ private fun StartSidePanel( selectedCategory: ShortcutCategoryType?, onCategoryClicked: (ShortcutCategoryUi) -> Unit, ) { - Column(modifier) { - ShortcutsSearchBar(onSearchQueryChanged) - Spacer(modifier = Modifier.heightIn(8.dp)) - CategoriesPanelTwoPane(categories, selectedCategory, onCategoryClicked) - Spacer(modifier = Modifier.weight(1f)) - KeyboardSettings( - horizontalPadding = 24.dp, - verticalPadding = 24.dp, - onKeyboardSettingsClicked, - ) + CompositionLocalProvider( + // Restrict system font scale increases up to a max so categories display correctly. + LocalDensity provides + Density( + density = LocalDensity.current.density, + fontScale = LocalDensity.current.fontScale.coerceIn(1f, 1.5f), + ) + ) { + Column(modifier) { + ShortcutsSearchBar(onSearchQueryChanged) + Spacer(modifier = Modifier.heightIn(8.dp)) + CategoriesPanelTwoPane(categories, selectedCategory, onCategoryClicked) + Spacer(modifier = Modifier.weight(1f)) + KeyboardSettings( + horizontalPadding = 24.dp, + verticalPadding = 24.dp, + onKeyboardSettingsClicked, + ) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt index e295564a740f..f9904f6f62bc 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutHelperUtils.kt @@ -49,5 +49,5 @@ fun getWidth(): Dp { object ShortcutHelperBottomSheet { val DefaultWidth = 412.dp val LargeScreenWidthPortrait = 704.dp - val LargeScreenWidthLandscape = 864.dp + val LargeScreenWidthLandscape = 960.dp } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 2ee9ddb0e453..01ec4d026646 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -2875,7 +2875,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) { - mKeyguardTransitions.startKeyguardTransition(showing, aodShowing); + startKeyguardTransition(showing, aodShowing); } else { try { @@ -3019,7 +3019,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, final int keyguardFlag = flags; mUiBgExecutor.execute(() -> { if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) { - mKeyguardTransitions.startKeyguardTransition( + startKeyguardTransition( false /* keyguardShowing */, false /* aodShowing */); return; } @@ -3035,6 +3035,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, } }; + private void startKeyguardTransition(boolean keyguardShowing, boolean aodShowing) { + mKeyguardTransitions.startKeyguardTransition(keyguardShowing, aodShowing); + } + private final Runnable mHideAnimationFinishedRunnable = () -> { Log.e(TAG, "mHideAnimationFinishedRunnable#run"); mHideAnimationRunning = false; @@ -3490,8 +3494,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable, mSurfaceBehindRemoteAnimationRequested = true; if (ENABLE_NEW_KEYGUARD_SHELL_TRANSITIONS) { - mKeyguardTransitions.startKeyguardTransition( - false /* keyguardShowing */, false /* aodShowing */); + startKeyguardTransition(false /* keyguardShowing */, false /* aodShowing */); return; } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt index 2914cb9fdfdc..a137d6cf91ec 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/WindowManagerLockscreenVisibilityManager.kt @@ -122,10 +122,7 @@ constructor( if (visible) { if (enableNewKeyguardShellTransitions) { - keyguardTransitions.startKeyguardTransition( - false /* keyguardShowing */, - false, /* aodShowing */ - ) + startKeyguardTransition(false, /* keyguardShowing */ false /* aodShowing */) isKeyguardGoingAway = true return } @@ -233,7 +230,7 @@ constructor( "aodVisible=$aodVisible).", ) if (enableNewKeyguardShellTransitions) { - keyguardTransitions.startKeyguardTransition(lockscreenShowing, aodVisible) + startKeyguardTransition(lockscreenShowing, aodVisible) } else { activityTaskManagerService.setLockScreenShown(lockscreenShowing, aodVisible) } @@ -241,6 +238,10 @@ constructor( this.isAodVisible = aodVisible } + private fun startKeyguardTransition(keyguardShowing: Boolean, aodShowing: Boolean) { + keyguardTransitions.startKeyguardTransition(keyguardShowing, aodShowing) + } + private fun endKeyguardGoingAwayAnimation() { if (!isKeyguardGoingAway) { Log.d( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt index 283651dd9db7..9718e7508df2 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardClockRepository.kt @@ -144,7 +144,7 @@ constructor( .stateIn( scope = applicationScope, started = SharingStarted.WhileSubscribed(), - initialValue = clockRegistry.createCurrentClock(), + initialValue = null, ) override val previewClock: Flow<ClockController> = diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt index 914fdd20e48e..6c03b2489380 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardPreviewClockViewBinder.kt @@ -151,7 +151,5 @@ object KeyguardPreviewClockViewBinder { cs.applyTo(rootView) } - private const val DATE_WEATHER_VIEW_HEIGHT = "date_weather_view_height" - private const val ENHANCED_SMARTSPACE_HEIGHT = "enhanced_smartspace_height" private const val TAG = "KeyguardPreviewClockViewBinder" } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt index 08c3f153bc4e..4c23adfe92e8 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/AodNotificationIconsSection.kt @@ -29,6 +29,7 @@ import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START import androidx.constraintlayout.widget.ConstraintSet.TOP import com.android.systemui.common.ui.ConfigurationState +import com.android.systemui.customization.R as customR import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel @@ -114,14 +115,14 @@ constructor( START, PARENT_ID, START, - context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal), + context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal), ) connect( nicId, END, PARENT_ID, END, - context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal), + context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal), ) constrainHeight( nicId, 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 c009720feaeb..6c98d5b01e4e 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 @@ -221,7 +221,9 @@ constructor( PARENT_ID, START, context.resources.getDimensionPixelSize(customR.dimen.clock_padding_start) + - context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal), + context.resources.getDimensionPixelSize( + customR.dimen.status_view_margin_horizontal + ), ) val smallClockTopMargin = keyguardClockViewModel.getSmallClockTopMargin() create(R.id.small_clock_guideline_top, ConstraintSet.HORIZONTAL_GUIDELINE) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt index 0782846f52ae..f0d21f22c5ee 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt @@ -28,6 +28,7 @@ import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID import androidx.constraintlayout.widget.ConstraintSet.START import androidx.constraintlayout.widget.ConstraintSet.TOP +import com.android.systemui.customization.R as customR import com.android.systemui.keyguard.MigrateClocksToBlueprint import com.android.systemui.keyguard.shared.model.KeyguardSection import com.android.systemui.media.controls.ui.controller.KeyguardMediaController @@ -42,7 +43,7 @@ class SplitShadeMediaSection constructor( @ShadeDisplayAware private val context: Context, private val notificationPanelView: NotificationPanelView, - private val keyguardMediaController: KeyguardMediaController + private val keyguardMediaController: KeyguardMediaController, ) : KeyguardSection() { private val mediaContainerId = R.id.status_view_media_container @@ -62,7 +63,7 @@ constructor( val horizontalPadding = padding + context.resources.getDimensionPixelSize( - R.dimen.status_view_margin_horizontal + customR.dimen.status_view_margin_horizontal ) setPaddingRelative(horizontalPadding, padding, horizontalPadding, padding) diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt index e30ddc69b19d..de0927ec27cb 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardSmartspaceViewModel.kt @@ -17,6 +17,7 @@ package com.android.systemui.keyguard.ui.viewmodel import android.content.Context +import com.android.systemui.customization.R as customR import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.keyguard.domain.interactor.KeyguardSmartspaceInteractor @@ -59,10 +60,9 @@ constructor( /** Whether the weather area should be visible. */ val isWeatherVisible: StateFlow<Boolean> = - combine( + combine(isWeatherEnabled, keyguardClockViewModel.hasCustomWeatherDataDisplay) { isWeatherEnabled, - keyguardClockViewModel.hasCustomWeatherDataDisplay, - ) { isWeatherEnabled, clockIncludesCustomWeatherDisplay -> + clockIncludesCustomWeatherDisplay -> isWeatherVisible( clockIncludesCustomWeatherDisplay = clockIncludesCustomWeatherDisplay, isWeatherEnabled = isWeatherEnabled, @@ -76,7 +76,7 @@ constructor( clockIncludesCustomWeatherDisplay = keyguardClockViewModel.hasCustomWeatherDataDisplay.value, isWeatherEnabled = smartspaceInteractor.isWeatherEnabled.value, - ) + ), ) private fun isWeatherVisible( @@ -92,12 +92,12 @@ constructor( companion object { fun getSmartspaceStartMargin(context: Context): Int { return context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start) + - context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal) + context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal) } fun getSmartspaceEndMargin(context: Context): Int { return context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end) + - context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal) + context.resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal) } } } diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java index 4c21da52db3a..8097d9585fb5 100644 --- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java +++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java @@ -32,8 +32,6 @@ import com.android.systemui.plugins.clocks.ClockMessageBuffers; import com.android.systemui.qs.QSFragmentLegacy; import com.android.systemui.qs.pipeline.shared.QSPipelineFlagsRepository; import com.android.systemui.qs.pipeline.shared.TileSpec; -import com.android.systemui.statusbar.notification.NotifPipelineFlags; -import com.android.systemui.util.Compile; import com.android.systemui.util.wakelock.WakeLockLog; import dagger.Lazy; @@ -56,61 +54,6 @@ public class LogModule { return factory.create("DozeLog", 150); } - /** Provides a logging buffer for all logs related to the data layer of notifications. */ - @Provides - @SysUISingleton - @NotificationLog - public static LogBuffer provideNotificationsLogBuffer( - LogBufferFactory factory, - NotifPipelineFlags notifPipelineFlags) { - int maxSize = 1000; - if (Compile.IS_DEBUG && notifPipelineFlags.isDevLoggingEnabled()) { - maxSize *= 10; - } - return factory.create("NotifLog", maxSize, Compile.IS_DEBUG /* systrace */); - } - - /** Provides a logging buffer for all logs related to notifications on the lockscreen. */ - @Provides - @SysUISingleton - @NotificationLockscreenLog - public static LogBuffer provideNotificationLockScreenLogBuffer( - LogBufferFactory factory) { - return factory.create("NotifLockscreenLog", 50, false /* systrace */); - } - - /** Provides a logging buffer for logs related to heads up presentation of notifications. */ - @Provides - @SysUISingleton - @NotificationHeadsUpLog - public static LogBuffer provideNotificationHeadsUpLogBuffer(LogBufferFactory factory) { - return factory.create("NotifHeadsUpLog", 1000); - } - - /** Provides a logging buffer for logs related to inflation of notifications. */ - @Provides - @SysUISingleton - @NotifInflationLog - public static LogBuffer provideNotifInflationLogBuffer(LogBufferFactory factory) { - return factory.create("NotifInflationLog", 250); - } - - /** Provides a logging buffer for notification interruption calculations. */ - @Provides - @SysUISingleton - @NotificationInterruptLog - public static LogBuffer provideNotificationInterruptLogBuffer(LogBufferFactory factory) { - return factory.create("NotifInterruptLog", 100); - } - - /** Provides a logging buffer for notification rendering events. */ - @Provides - @SysUISingleton - @NotificationRenderLog - public static LogBuffer provideNotificationRenderLogBuffer(LogBufferFactory factory) { - return factory.create("NotifRenderLog", 100); - } - /** Provides a logging buffer for all logs for lockscreen to shade transition events. */ @Provides @SysUISingleton @@ -119,16 +62,6 @@ public class LogModule { return factory.create("LSShadeTransitionLog", 50); } - /** */ - @Provides - @SysUISingleton - @SensitiveNotificationProtectionLog - public static LogBuffer provideSensitiveNotificationProtectionLogBuffer( - LogBufferFactory factory - ) { - return factory.create("SensitiveNotificationProtectionLog", 10); - } - /** Provides a logging buffer for shade window messages. */ @Provides @SysUISingleton @@ -153,30 +86,6 @@ public class LogModule { return factory.create("ShadeTouchLog", 500, false); } - /** Provides a logging buffer for all logs related to managing notification sections. */ - @Provides - @SysUISingleton - @NotificationSectionLog - public static LogBuffer provideNotificationSectionLogBuffer(LogBufferFactory factory) { - return factory.create("NotifSectionLog", 1000 /* maxSize */, false /* systrace */); - } - - /** Provides a logging buffer for all logs related to remote input controller. */ - @Provides - @SysUISingleton - @NotificationRemoteInputLog - public static LogBuffer provideNotificationRemoteInputLogBuffer(LogBufferFactory factory) { - return factory.create("NotifRemoteInputLog", 50 /* maxSize */, false /* systrace */); - } - - /** Provides a logging buffer for all logs related to notification visual stability. */ - @Provides - @SysUISingleton - @VisualStabilityLog - public static LogBuffer provideVisualStabilityLogBuffer(LogBufferFactory factory) { - return factory.create("VisualStabilityLog", 50 /* maxSize */, false /* systrace */); - } - /** Provides a logging buffer for all logs related to keyguard media controller. */ @Provides @SysUISingleton @@ -185,22 +94,6 @@ public class LogModule { return factory.create("KeyguardMediaControllerLog", 50 /* maxSize */, false /* systrace */); } - /** Provides a logging buffer for all logs related to unseen notifications. */ - @Provides - @SysUISingleton - @UnseenNotificationLog - public static LogBuffer provideUnseenNotificationLogBuffer(LogBufferFactory factory) { - return factory.create("UnseenNotifLog", 20 /* maxSize */, false /* systrace */); - } - - /** Provides a logging buffer for all logs related to the data layer of notifications. */ - @Provides - @SysUISingleton - @NotifInteractionLog - public static LogBuffer provideNotifInteractionLogBuffer(LogBufferFactory factory) { - return factory.create("NotifInteractionLog", 50); - } - /** Provides a logging buffer for all logs related to Quick Settings. */ @Provides @SysUISingleton diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt index 9029563b6321..e3de6d5152e4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt @@ -62,6 +62,7 @@ import com.android.systemui.shade.transition.LargeScreenShadeInterpolator import com.android.systemui.statusbar.StatusBarState import com.android.systemui.statusbar.SysuiStatusBarStateController import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository +import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor import com.android.systemui.util.LargeScreenUtils import com.android.systemui.util.asIndenting import com.android.systemui.util.kotlin.emitOnStart @@ -93,7 +94,7 @@ constructor( private val footerActionsController: FooterActionsController, private val sysuiStatusBarStateController: SysuiStatusBarStateController, deviceEntryInteractor: DeviceEntryInteractor, - disableFlagsRepository: DisableFlagsRepository, + DisableFlagsInteractor: DisableFlagsInteractor, keyguardTransitionInteractor: KeyguardTransitionInteractor, private val largeScreenShadeInterpolator: LargeScreenShadeInterpolator, @ShadeDisplayAware configurationInteractor: ConfigurationInteractor, @@ -182,8 +183,8 @@ constructor( val isQsEnabled by hydrator.hydratedStateOf( traceName = "isQsEnabled", - initialValue = disableFlagsRepository.disableFlags.value.isQuickSettingsEnabled(), - source = disableFlagsRepository.disableFlags.map { it.isQuickSettingsEnabled() }, + initialValue = DisableFlagsInteractor.disableFlags.value.isQuickSettingsEnabled(), + source = DisableFlagsInteractor.disableFlags.map { it.isQuickSettingsEnabled() }, ) var isInSplitShade by mutableStateOf(false) diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt index 0e09ad29f4fd..dbad60265645 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt @@ -17,6 +17,7 @@ package com.android.systemui.qs.panels.ui.compose.infinitegrid import android.graphics.drawable.Animatable +import android.graphics.drawable.AnimatedVectorDrawable import android.graphics.drawable.Drawable import android.text.TextUtils import androidx.compose.animation.animateColorAsState @@ -228,7 +229,14 @@ fun SmallTileContent( } } } - is Icon.Loaded -> rememberDrawablePainter(loadedDrawable) + is Icon.Loaded -> { + LaunchedEffect(loadedDrawable) { + if (loadedDrawable is AnimatedVectorDrawable) { + loadedDrawable.forceAnimationOnUI() + } + } + rememberDrawablePainter(loadedDrawable) + } } Image( diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java index 301ab2bcdd65..8f6c4e743269 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java @@ -1429,7 +1429,7 @@ public class InternetDialogController implements AccessPointController.AccessPoi void makeOverlayToast(int stringId) { final Resources res = mContext.getResources(); - final SystemUIToast systemUIToast = mToastFactory.createToast(mContext, + final SystemUIToast systemUIToast = mToastFactory.createToast(mContext, mContext, res.getString(stringId), mContext.getPackageName(), UserHandle.myUserId(), res.getConfiguration().orientation); if (systemUIToast == null) { diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayCoreStartable.kt new file mode 100644 index 000000000000..bc15bbb5e57d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayCoreStartable.kt @@ -0,0 +1,89 @@ +/* + * 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.reardisplay + +import android.content.Context +import android.hardware.devicestate.DeviceStateManager +import android.hardware.devicestate.feature.flags.Flags +import androidx.annotation.VisibleForTesting +import com.android.systemui.CoreStartable +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor +import com.android.systemui.statusbar.phone.SystemUIDialog +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map + +/** + * Provides a {@link com.android.systemui.statusbar.phone.SystemUIDialog} to be shown on the inner + * display when the device enters Rear Display Mode, containing an UI affordance to let the user + * know that the main content has moved to the outer display, as well as an UI affordance to cancel + * the Rear Display Mode. + */ +@SysUISingleton +class RearDisplayCoreStartable +@Inject +internal constructor( + private val context: Context, + private val deviceStateManager: DeviceStateManager, + private val rearDisplayStateInteractor: RearDisplayStateInteractor, + private val rearDisplayInnerDialogDelegateFactory: RearDisplayInnerDialogDelegate.Factory, + @Application private val scope: CoroutineScope, +) : CoreStartable, AutoCloseable { + + companion object { + private const val TAG: String = "RearDisplayCoreStartable" + } + + @VisibleForTesting var stateChangeListener: Job? = null + + override fun close() { + stateChangeListener?.cancel() + } + + override fun start() { + if (Flags.deviceStateRdmV2()) { + var dialog: SystemUIDialog? = null + + stateChangeListener = + rearDisplayStateInteractor.state + .map { + when (it) { + is RearDisplayStateInteractor.State.Enabled -> { + val rearDisplayContext = + context.createDisplayContext(it.innerDisplay) + val delegate = + rearDisplayInnerDialogDelegateFactory.create( + rearDisplayContext, + deviceStateManager::cancelStateRequest, + ) + dialog = delegate.createDialog().apply { show() } + } + + is RearDisplayStateInteractor.State.Disabled -> { + dialog?.dismiss() + dialog = null + } + } + } + .launchIn(scope) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegate.kt b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegate.kt new file mode 100644 index 000000000000..2d6181aa04af --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegate.kt @@ -0,0 +1,62 @@ +/* + * 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.reardisplay + +import android.content.Context +import android.os.Bundle +import android.view.View +import com.android.systemui.res.R +import com.android.systemui.statusbar.phone.SystemUIDialog +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject + +/** + * A {@link com.android.systemui.statusbar.phone.SystemUIDialog.Delegate} providing a dialog which + * lets the user know that the Rear Display Mode is active, and that the content has moved to the + * outer display. + */ +class RearDisplayInnerDialogDelegate +@AssistedInject +internal constructor( + private val systemUIDialogFactory: SystemUIDialog.Factory, + @Assisted private val rearDisplayContext: Context, + @Assisted private val onCanceledRunnable: Runnable, +) : SystemUIDialog.Delegate { + + @AssistedFactory + interface Factory { + fun create( + rearDisplayContext: Context, + onCanceledRunnable: Runnable, + ): RearDisplayInnerDialogDelegate + } + + override fun createDialog(): SystemUIDialog { + return systemUIDialogFactory.create(this, rearDisplayContext) + } + + override fun onCreate(dialog: SystemUIDialog, savedInstanceState: Bundle?) { + dialog.apply { + setContentView(R.layout.activity_rear_display_front_screen_on) + setCanceledOnTouchOutside(false) + requireViewById<View>(R.id.button_cancel).setOnClickListener { + onCanceledRunnable.run() + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt index 6ab294dd9818..5fb9cb27f90f 100644 --- a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt +++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayModule.kt @@ -41,4 +41,10 @@ interface RearDisplayModule { fun bindRearDisplayDialogControllerConfigChanges( impl: RearDisplayDialogController ): ConfigurationListener + + /** Start RearDisplayCoreStartable. */ + @Binds + @IntoMap + @ClassKey(RearDisplayCoreStartable::class) + abstract fun bindRearDisplayCoreStartable(impl: RearDisplayCoreStartable): CoreStartable } diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt index 667827ac4724..c96ea03f057a 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/interactor/SceneContainerOcclusionInteractor.kt @@ -138,6 +138,7 @@ constructor( Overlays.QuickSettingsShade -> false Scenes.Bouncer -> false Scenes.Communal -> true + Scenes.Dream -> false Scenes.Gone -> true Scenes.Lockscreen -> true Scenes.QuickSettings -> false diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt index 41a3c8aff6cf..b89eb5c762e0 100644 --- a/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt +++ b/packages/SystemUI/src/com/android/systemui/scene/domain/resolver/HomeSceneFamilyResolver.kt @@ -23,6 +23,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.keyguard.domain.interactor.KeyguardEnabledInteractor +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import dagger.Binds @@ -46,6 +47,7 @@ class HomeSceneFamilyResolver constructor( @Application private val applicationScope: CoroutineScope, deviceEntryInteractor: DeviceEntryInteractor, + keyguardInteractor: KeyguardInteractor, keyguardEnabledInteractor: KeyguardEnabledInteractor, ) : SceneResolver { override val targetFamily: SceneKey = SceneFamilies.Home @@ -56,6 +58,7 @@ constructor( deviceEntryInteractor.canSwipeToEnter, deviceEntryInteractor.isDeviceEntered, deviceEntryInteractor.isUnlocked, + keyguardInteractor.isDreamingWithOverlay, transform = ::homeScene, ) .stateIn( @@ -67,7 +70,8 @@ constructor( canSwipeToEnter = deviceEntryInteractor.canSwipeToEnter.value, isDeviceEntered = deviceEntryInteractor.isDeviceEntered.value, isUnlocked = deviceEntryInteractor.isUnlocked.value, - ) + isDreamingWithOverlay = false, + ), ) override fun includesScene(scene: SceneKey): Boolean = scene in homeScenes @@ -77,8 +81,11 @@ constructor( canSwipeToEnter: Boolean?, isDeviceEntered: Boolean, isUnlocked: Boolean, + isDreamingWithOverlay: Boolean, ): SceneKey = when { + // Dream can run even if Keyguard is disabled, thus it has the highest priority here. + isDreamingWithOverlay -> Scenes.Dream !isKeyguardEnabled -> Scenes.Gone canSwipeToEnter == true -> Scenes.Lockscreen !isDeviceEntered -> Scenes.Lockscreen @@ -91,6 +98,9 @@ constructor( setOf( Scenes.Gone, Scenes.Lockscreen, + // Dream is a home scene as the dream activity occludes keyguard and can show the + // shade on top. + Scenes.Dream, ) } } 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 daeaaa52fd94..9125d7e8bb0e 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 @@ -62,6 +62,7 @@ import com.android.systemui.scene.session.shared.SessionStorage import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.shared.logger.SceneLogger import com.android.systemui.scene.shared.model.Overlays +import com.android.systemui.scene.shared.model.SceneFamilies import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.domain.interactor.ShadeInteractor import com.android.systemui.statusbar.NotificationShadeWindowController @@ -217,7 +218,9 @@ constructor( sceneInteractor.transitionState.mapNotNull { state -> when (state) { is ObservableTransitionState.Idle -> { - if (state.currentScene != Scenes.Gone) { + if (state.currentScene == Scenes.Dream) { + false to "dream is showing" + } else if (state.currentScene != Scenes.Gone) { true to "scene is not Gone" } else if (state.currentOverlays.isNotEmpty()) { true to "overlay is shown" @@ -228,21 +231,30 @@ constructor( is ObservableTransitionState.Transition -> { if (state.fromContent == Scenes.Gone) { true to "scene transitioning away from Gone" + } else if (state.fromContent == Scenes.Dream) { + true to "scene transitioning away from dream" } else { null } } } }, + sceneInteractor.transitionState.map { state -> + state.isTransitioningFromOrTo(Scenes.Communal) || + state.isIdle(Scenes.Communal) + }, headsUpInteractor.isHeadsUpOrAnimatingAway, occlusionInteractor.invisibleDueToOcclusion, alternateBouncerInteractor.isVisible, ) { visibilityForTransitionState, + isCommunalShowing, isHeadsUpOrAnimatingAway, invisibleDueToOcclusion, isAlternateBouncerVisible -> when { + isCommunalShowing -> + true to "on or transitioning to/from communal" isHeadsUpOrAnimatingAway -> true to "showing a HUN" isAlternateBouncerVisible -> true to "showing alternate bouncer" invisibleDueToOcclusion -> false to "invisible due to occlusion" @@ -266,6 +278,7 @@ constructor( handleSimUnlock() handleDeviceUnlockStatus() handlePowerState() + handleDreamState() handleShadeTouchability() } @@ -506,6 +519,31 @@ constructor( } } + private fun handleDreamState() { + applicationScope.launch { + keyguardInteractor.isAbleToDream + .sample(sceneInteractor.transitionState, ::Pair) + .collect { (isAbleToDream, transitionState) -> + if (transitionState.isIdle(Scenes.Communal)) { + // The dream is automatically started underneath the hub, don't transition + // to dream when this is happening as communal is still visible on top. + return@collect + } + if (isAbleToDream) { + switchToScene( + targetSceneKey = Scenes.Dream, + loggingReason = "dream started", + ) + } else { + switchToScene( + targetSceneKey = SceneFamilies.Home, + loggingReason = "dream stopped", + ) + } + } + } + } + private fun handleShadeTouchability() { applicationScope.launch { shadeInteractor.isShadeTouchable diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java index 3a90d2b9df7b..503d0bfbc301 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java @@ -235,8 +235,7 @@ public class BrightnessSliderController extends ViewController<BrightnessSliderV if (mBrightnessWarningToast.isToastActive()) { return; } - mBrightnessWarningToast.show(mView.getContext(), - R.string.quick_settings_brightness_unable_adjust_msg); + mBrightnessWarningToast.show(mView.getContext(), resId); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt b/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt index dfbdaa62ec44..40260d0ca29f 100644 --- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt +++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ui/BrightnessWarningToast.kt @@ -37,11 +37,14 @@ constructor( private var toastView: View? = null fun show(viewContext: Context, @StringRes resId: Int) { + if (isToastActive()) { + return + } val res = viewContext.resources // Show the brightness warning toast with passing the toast inflation required context, // userId and resId from SystemUI package. val systemUIToast = toastFactory.createToast( - viewContext, + viewContext, viewContext, res.getString(resId), viewContext.packageName, viewContext.getUserId(), res.configuration.orientation ) @@ -79,13 +82,15 @@ constructor( val inAnimator = systemUIToast.inAnimation inAnimator?.start() - toastView!!.postDelayed({ + toastView?.postDelayed({ val outAnimator = systemUIToast.outAnimation if (outAnimator != null) { outAnimator.start() outAnimator.addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animator: Animator) { - windowManager.removeViewImmediate(toastView) + if (isToastActive()) { + windowManager.removeViewImmediate(toastView) + } toastView = null } }) @@ -94,7 +99,7 @@ constructor( } fun isToastActive(): Boolean { - return toastView != null && toastView!!.isAttachedToWindow + return toastView?.isAttachedToWindow == true } companion object { diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java index 0e82bf82fdf9..4ccd2b93911e 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java @@ -3109,12 +3109,18 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump if (isTracking()) { onTrackingStopped(true); } - if (isExpanded() && !mQsController.getExpanded()) { + if (isExpanded() && mBarState != KEYGUARD && !mQsController.getExpanded()) { mShadeLog.d("Status Bar was long pressed. Expanding to QS."); expandToQs(); } else { - mShadeLog.d("Status Bar was long pressed. Expanding to Notifications."); - expandToNotifications(); + if (mBarState == KEYGUARD) { + mShadeLog.d("Lockscreen Status Bar was long pressed. Expanding to Notifications."); + mLockscreenShadeTransitionController.goToLockedShade( + /* expandedView= */null, /* needsQSAnimation= */false); + } else { + mShadeLog.d("Status Bar was long pressed. Expanding to Notifications."); + expandToNotifications(); + } } } @@ -5091,13 +5097,6 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump } boolean handled = mHeadsUpTouchHelper.onTouchEvent(event); - if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && mQsController.handleTouch( - event, isFullyCollapsed(), isShadeOrQsHeightAnimationRunning())) { - if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { - mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event"); - } - return true; - } // This touch session has already resulted in shade expansion. Ignore everything else. if (ShadeExpandsOnStatusBarLongPress.isEnabled() && event.getActionMasked() != MotionEvent.ACTION_DOWN @@ -5105,6 +5104,13 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump mShadeLog.d("Touch has same down time as Status Bar long press. Ignoring."); return false; } + if (!mHeadsUpTouchHelper.isTrackingHeadsUp() && mQsController.handleTouch( + event, isFullyCollapsed(), isShadeOrQsHeightAnimationRunning())) { + if (event.getActionMasked() != MotionEvent.ACTION_MOVE) { + mShadeLog.logMotionEvent(event, "onTouch: handleQsTouch handled event"); + } + return true; + } if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) { mMetricsLogger.count(COUNTER_PANEL_OPEN, 1); handled = true; diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt index 7a18d7caa13f..207439e1f374 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationsQSContainerController.kt @@ -28,6 +28,7 @@ import androidx.constraintlayout.widget.ConstraintSet.START import androidx.constraintlayout.widget.ConstraintSet.TOP import androidx.lifecycle.lifecycleScope import com.android.app.tracing.coroutines.launchTraced as launch +import com.android.systemui.customization.R as customR import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.fragments.FragmentService @@ -314,7 +315,7 @@ constructor( private fun setKeyguardStatusViewConstraints(constraintSet: ConstraintSet) { val statusViewMarginHorizontal = - resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal) + resources.getDimensionPixelSize(customR.dimen.status_view_margin_horizontal) constraintSet.apply { setMargin(R.id.keyguard_status_view, START, statusViewMarginHorizontal) setMargin(R.id.keyguard_status_view, END, statusViewMarginHorizontal) diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt index e15830eb22eb..fed4a26ab1ab 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt @@ -30,8 +30,8 @@ import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractorImpl import com.android.systemui.dagger.SysUISingleton import com.android.systemui.res.R -import com.android.systemui.shade.data.repository.ShadePositionRepository -import com.android.systemui.shade.data.repository.ShadePositionRepositoryImpl +import com.android.systemui.shade.data.repository.ShadeDisplaysRepository +import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround import com.android.systemui.statusbar.phone.ConfigurationControllerImpl import com.android.systemui.statusbar.phone.ConfigurationForwarder @@ -157,16 +157,16 @@ object ShadeDisplayAwareModule { @SysUISingleton @Provides - fun provideShadePositionRepository(impl: ShadePositionRepositoryImpl): ShadePositionRepository { + fun provideShadePositionRepository(impl: ShadeDisplaysRepositoryImpl): ShadeDisplaysRepository { ShadeWindowGoesAround.isUnexpectedlyInLegacyMode() return impl } @Provides @IntoMap - @ClassKey(ShadePositionRepositoryImpl::class) + @ClassKey(ShadeDisplaysRepositoryImpl::class) fun provideShadePositionRepositoryAsCoreStartable( - impl: ShadePositionRepositoryImpl + impl: ShadeDisplaysRepositoryImpl ): CoreStartable { return if (ShadeWindowGoesAround.isEnabled) { impl diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt index 802fc0edb533..506b4e9ab565 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/ShadePrimaryDisplayCommand.kt @@ -17,11 +17,11 @@ package com.android.systemui.shade import android.view.Display -import com.android.systemui.shade.data.repository.ShadePositionRepository +import com.android.systemui.shade.data.repository.ShadeDisplaysRepository import com.android.systemui.statusbar.commandline.Command import java.io.PrintWriter -class ShadePrimaryDisplayCommand(private val positionRepository: ShadePositionRepository) : +class ShadePrimaryDisplayCommand(private val positionRepository: ShadeDisplaysRepository) : Command { override fun execute(pw: PrintWriter, args: List<String>) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/LongPressGestureDetector.kt b/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt index 6fb3ca5f86d2..ae36e81c7b1f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/LongPressGestureDetector.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/StatusBarLongPressGestureDetector.kt @@ -25,7 +25,7 @@ import javax.inject.Inject /** Accepts touch events, detects long press, and calls ShadeViewController#onStatusBarLongPress. */ @SysUISingleton -class LongPressGestureDetector +class StatusBarLongPressGestureDetector @Inject constructor(context: Context, val shadeViewController: ShadeViewController) { val gestureDetector = diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadePositionRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt index 37210b90ee78..71c565816362 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadePositionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt @@ -20,7 +20,7 @@ import android.view.Display import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -class FakeShadePositionRepository : ShadePositionRepository { +class FakeShadeDisplayRepository : ShadeDisplaysRepository { private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY) override fun setDisplayId(displayId: Int) { diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadePositionRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt index 24c067ae2371..e920abac8ccc 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadePositionRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt @@ -25,7 +25,7 @@ import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -interface ShadePositionRepository { +interface ShadeDisplaysRepository { /** ID of the display which currently hosts the shade */ val displayId: StateFlow<Int> @@ -41,9 +41,9 @@ interface ShadePositionRepository { /** Source of truth for the display currently holding the shade. */ @SysUISingleton -class ShadePositionRepositoryImpl +class ShadeDisplaysRepositoryImpl @Inject -constructor(private val commandRegistry: CommandRegistry) : ShadePositionRepository, CoreStartable { +constructor(private val commandRegistry: CommandRegistry) : ShadeDisplaysRepository, CoreStartable { private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY) override val displayId: StateFlow<Int> diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt index 4e7898d2fd2d..1055dcb55d5f 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt @@ -30,7 +30,7 @@ import com.android.systemui.display.shared.model.DisplayWindowProperties import com.android.systemui.scene.ui.view.WindowRootView import com.android.systemui.shade.ShadeDisplayAware import com.android.systemui.shade.ShadeWindowLayoutParams -import com.android.systemui.shade.data.repository.ShadePositionRepository +import com.android.systemui.shade.data.repository.ShadeDisplaysRepository import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround import com.android.systemui.statusbar.phone.ConfigurationForwarder import javax.inject.Inject @@ -38,13 +38,13 @@ import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.withContext -/** Handles Shade window display change when [ShadePositionRepository.displayId] changes. */ +/** Handles Shade window display change when [ShadeDisplaysRepository.displayId] changes. */ @SysUISingleton class ShadeDisplaysInteractor @Inject constructor( private val shadeRootView: WindowRootView, - private val shadePositionRepository: ShadePositionRepository, + private val shadePositionRepository: ShadeDisplaysRepository, @ShadeDisplayAware private val shadeContext: Context, private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository, @Background private val bgScope: CoroutineScope, diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt index 460bfbbcb3ab..a653ca2f80a9 100644 --- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt @@ -25,7 +25,7 @@ import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.Edge import com.android.systemui.keyguard.shared.model.KeyguardState import com.android.systemui.power.domain.interactor.PowerInteractor -import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository +import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor import com.android.systemui.statusbar.phone.DozeParameters import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository import com.android.systemui.statusbar.policy.domain.interactor.DeviceProvisioningInteractor @@ -47,7 +47,7 @@ class ShadeInteractorImpl constructor( @Application val scope: CoroutineScope, deviceProvisioningInteractor: DeviceProvisioningInteractor, - disableFlagsRepository: DisableFlagsRepository, + disableFlagsInteractor: DisableFlagsInteractor, dozeParams: DozeParameters, keyguardRepository: KeyguardRepository, keyguardTransitionInteractor: KeyguardTransitionInteractor, @@ -61,13 +61,13 @@ constructor( BaseShadeInteractor by baseShadeInteractor, ShadeModeInteractor by shadeModeInteractor { override val isShadeEnabled: StateFlow<Boolean> = - disableFlagsRepository.disableFlags + disableFlagsInteractor.disableFlags .map { it.isShadeEnabled() } .flowName("isShadeEnabled") .stateIn(scope, SharingStarted.Eagerly, initialValue = false) override val isQsEnabled: StateFlow<Boolean> = - disableFlagsRepository.disableFlags + disableFlagsInteractor.disableFlags .map { it.isQuickSettingsEnabled() } .flowName("isQsEnabled") .stateIn(scope, SharingStarted.Eagerly, initialValue = false) @@ -114,7 +114,7 @@ constructor( override val isExpandToQsEnabled: Flow<Boolean> = combine( - disableFlagsRepository.disableFlags, + disableFlagsInteractor.disableFlags, isShadeEnabled, keyguardRepository.isDozing, userSetupRepository.isUserSetUp, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index 33f0c64269cc..6bec86a67e9c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -177,8 +177,6 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi private float[] mMatrix; private ColorMatrixColorFilter mMatrixColorFilter; private Runnable mLayoutRunnable; - private boolean mDismissed; - private Runnable mOnDismissListener; private boolean mIncreasedSize; private boolean mShowsConversation; private float mDozeAmount; @@ -956,21 +954,6 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi mLayoutRunnable = runnable; } - public void setDismissed() { - mDismissed = true; - if (mOnDismissListener != null) { - mOnDismissListener.run(); - } - } - - public boolean isDismissed() { - return mDismissed; - } - - public void setOnDismissListener(Runnable onDismissListener) { - mOnDismissListener = onDismissListener; - } - @Override public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) { int areaTint = getTint(areas, this, tint); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java index da04f6edf9e2..b2ca33a4aecf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java @@ -705,6 +705,7 @@ public class StatusBarStateControllerImpl implements final boolean onBouncer = currentScene.equals(Scenes.Bouncer); final boolean onCommunal = currentScene.equals(Scenes.Communal); final boolean onGone = currentScene.equals(Scenes.Gone); + final boolean onDream = currentScene.equals(Scenes.Dream); final boolean onLockscreen = currentScene.equals(Scenes.Lockscreen); final boolean onQuickSettings = currentScene.equals(Scenes.QuickSettings); final boolean onShade = currentScene.equals(Scenes.Shade); @@ -765,6 +766,8 @@ public class StatusBarStateControllerImpl implements // We get here if deviceUnlockStatus.isUnlocked is false but we are no longer on or over // a keyguardish scene; we want to return SHADE_LOCKED until isUnlocked is also true. newState = StatusBarState.SHADE_LOCKED; + } else if (onDream) { + newState = StatusBarState.SHADE_LOCKED; } else { throw new IllegalArgumentException( "unhandled input to calculateStateFromSceneFramework: " + inputLogString); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt index 9004e5d12663..aeeb0427d24b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/repository/DisableFlagsRepository.kt @@ -22,7 +22,7 @@ import com.android.systemui.log.LogBuffer import com.android.systemui.log.dagger.DisableFlagsRepositoryLog import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.disableflags.DisableFlagsLogger -import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler import javax.inject.Inject import kotlinx.coroutines.CoroutineScope diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractor.kt new file mode 100644 index 000000000000..4f1b97841fde --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractor.kt @@ -0,0 +1,29 @@ +/* + * 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.disableflags.domain.interactor + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel +import javax.inject.Inject +import kotlinx.coroutines.flow.StateFlow + +@SysUISingleton +class DisableFlagsInteractor @Inject constructor(repository: DisableFlagsRepository) { + /** A model of the disable flags last received from [IStatusBar]. */ + val disableFlags: StateFlow<DisableFlagsModel> = repository.disableFlags +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/shared/model/DisableFlagsModel.kt index ce25cf5895c1..6507237cfc24 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/data/model/DisableFlagsModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/disableflags/shared/model/DisableFlagsModel.kt @@ -1,18 +1,20 @@ /* - * Copyright (C) 2023 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 + * 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. + * 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.disableflags.data.model +package com.android.systemui.statusbar.disableflags.shared.model import android.app.StatusBarManager.DISABLE2_NONE import android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 684ce48d9c7f..42aadd132cd8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -76,6 +76,7 @@ import com.android.systemui.statusbar.notification.interruption.VisualInterrupti import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor; import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger; import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl; +import com.android.systemui.statusbar.notification.logging.dagger.NotificationsLogModule; import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactory; import com.android.systemui.statusbar.notification.row.NotificationEntryProcessorFactoryLooperImpl; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -116,6 +117,7 @@ import javax.inject.Provider; ActivatableNotificationViewModelModule.class, NotificationMemoryModule.class, NotificationStatsLoggerModule.class, + NotificationsLogModule.class, }) public interface NotificationsModule { @Binds diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt index 8079ce540e1b..4ea597a12ebf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/NotificationAlertsInteractor.kt @@ -17,17 +17,15 @@ package com.android.systemui.statusbar.notification.domain.interactor import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository +import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor import javax.inject.Inject /** Interactor for notification alerting. */ @SysUISingleton class NotificationAlertsInteractor @Inject -constructor( - private val disableFlagsRepository: DisableFlagsRepository, -) { +constructor(private val disableFlagsInteractor: DisableFlagsInteractor) { /** Returns true if notification alerts are allowed. */ fun areNotificationAlertsEnabled(): Boolean = - disableFlagsRepository.disableFlags.value.areNotificationAlertsEnabled() + disableFlagsInteractor.disableFlags.value.areNotificationAlertsEnabled() } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/dagger/NotificationsLogModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/dagger/NotificationsLogModule.kt new file mode 100644 index 000000000000..d3359d39e959 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/dagger/NotificationsLogModule.kt @@ -0,0 +1,152 @@ +/* + * 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.logging.dagger + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.log.LogBuffer +import com.android.systemui.log.LogBufferFactory +import com.android.systemui.log.dagger.NotifInflationLog +import com.android.systemui.log.dagger.NotifInteractionLog +import com.android.systemui.log.dagger.NotificationHeadsUpLog +import com.android.systemui.log.dagger.NotificationInterruptLog +import com.android.systemui.log.dagger.NotificationLockscreenLog +import com.android.systemui.log.dagger.NotificationLog +import com.android.systemui.log.dagger.NotificationRemoteInputLog +import com.android.systemui.log.dagger.NotificationRenderLog +import com.android.systemui.log.dagger.NotificationSectionLog +import com.android.systemui.log.dagger.SensitiveNotificationProtectionLog +import com.android.systemui.log.dagger.UnseenNotificationLog +import com.android.systemui.log.dagger.VisualStabilityLog +import com.android.systemui.statusbar.notification.NotifPipelineFlags +import com.android.systemui.statusbar.notification.promoted.PromotedNotificationLog +import com.android.systemui.util.Compile +import dagger.Module +import dagger.Provides + +@Module +object NotificationsLogModule { + /** Provides a logging buffer for logs related to heads up presentation of notifications. */ + @Provides + @SysUISingleton + @NotificationHeadsUpLog + fun provideNotificationHeadsUpLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("NotifHeadsUpLog", 1000) + } + + /** Provides a logging buffer for logs related to inflation of notifications. */ + @Provides + @SysUISingleton + @NotifInflationLog + fun provideNotifInflationLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("NotifInflationLog", 250) + } + + /** Provides a logging buffer for all logs related to the data layer of notifications. */ + @Provides + @SysUISingleton + @NotifInteractionLog + fun provideNotifInteractionLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("NotifInteractionLog", 50) + } + + /** Provides a logging buffer for notification interruption calculations. */ + @Provides + @SysUISingleton + @NotificationInterruptLog + fun provideNotificationInterruptLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("NotifInterruptLog", 100) + } + + /** Provides a logging buffer for all logs related to notifications on the lockscreen. */ + @Provides + @SysUISingleton + @NotificationLockscreenLog + fun provideNotificationLockScreenLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("NotifLockscreenLog", 50, false /* systrace */) + } + + /** Provides a logging buffer for all logs related to the data layer of notifications. */ + @Provides + @SysUISingleton + @NotificationLog + fun provideNotificationsLogBuffer( + factory: LogBufferFactory, + notifPipelineFlags: NotifPipelineFlags, + ): LogBuffer { + var maxSize = 1000 + if (Compile.IS_DEBUG && notifPipelineFlags.isDevLoggingEnabled()) { + maxSize *= 10 + } + return factory.create("NotifLog", maxSize, Compile.IS_DEBUG /* systrace */) + } + + /** Provides a logging buffer for all logs related to remote input controller. */ + @Provides + @SysUISingleton + @NotificationRemoteInputLog + fun provideNotificationRemoteInputLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("NotifRemoteInputLog", 50, /* maxSize */ false /* systrace */) + } + + /** Provides a logging buffer for notification rendering events. */ + @Provides + @SysUISingleton + @NotificationRenderLog + fun provideNotificationRenderLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("NotifRenderLog", 100) + } + + /** Provides a logging buffer for all logs related to managing notification sections. */ + @Provides + @SysUISingleton + @NotificationSectionLog + fun provideNotificationSectionLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("NotifSectionLog", 1000, /* maxSize */ false /* systrace */) + } + + /** Provides a [LogBuffer] for use by promoted notifications. */ + @Provides + @SysUISingleton + @PromotedNotificationLog + fun providesPromotedNotificationLog(factory: LogBufferFactory): LogBuffer { + return factory.create("PromotedNotifLog", 50) + } + + /** */ + @Provides + @SysUISingleton + @SensitiveNotificationProtectionLog + fun provideSensitiveNotificationProtectionLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("SensitiveNotificationProtectionLog", 10) + } + + /** Provides a logging buffer for all logs related to unseen notifications. */ + @Provides + @SysUISingleton + @UnseenNotificationLog + fun provideUnseenNotificationLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("UnseenNotifLog", 20, /* maxSize */ false /* systrace */) + } + + /** Provides a logging buffer for all logs related to notification visual stability. */ + @Provides + @SysUISingleton + @VisualStabilityLog + fun provideVisualStabilityLogBuffer(factory: LogBufferFactory): LogBuffer { + return factory.create("VisualStabilityLog", 50, /* maxSize */ false /* systrace */) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLog.kt new file mode 100644 index 000000000000..f9d9c9771e67 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationLog.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.statusbar.notification.promoted + +import javax.inject.Qualifier + +/** A [com.android.systemui.log.LogBuffer] for use by promoted notifications. */ +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class PromotedNotificationLog 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 08d177f933c1..d1de6be27296 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 @@ -1543,7 +1543,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView setDragController(null); mGroupParentWhenDismissed = mNotificationParent; mChildAfterViewWhenDismissed = null; - mEntry.getIcons().getStatusBarIcon().setDismissed(); if (isChildInGroup()) { List<ExpandableNotificationRow> notificationChildren = mNotificationParent.getAttachedChildren(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 9166e7e9bed2..786d7d9ea0f3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -573,8 +573,29 @@ public class NotificationContentView extends FrameLayout implements Notification return; } - mUiEventLogger.log( - NotificationCompactHeadsUpEvent.NOTIFICATION_COMPACT_HUN_SHOWN); + final StatusBarNotification containingRowSbn = getContainingRowSbn(); + if (containingRowSbn == null) { + return; + } + + mUiEventLogger.logWithInstanceId( + NotificationCompactHeadsUpEvent.NOTIFICATION_COMPACT_HUN_SHOWN, + containingRowSbn.getUid(), + containingRowSbn.getPackageName(), + containingRowSbn.getInstanceId()); + } + + @Nullable + private StatusBarNotification getContainingRowSbn() { + if (mContainingNotification == null) { + return null; + } + final NotificationEntry entry = mContainingNotification.getEntry(); + if (entry == null) { + return null; + } + + return entry.getSbn(); } /** 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 db294934c9ed..80c8e8b2a109 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -171,12 +171,14 @@ import com.android.systemui.shade.NotificationShadeWindowView; import com.android.systemui.shade.NotificationShadeWindowViewController; import com.android.systemui.shade.QuickSettingsController; import com.android.systemui.shade.ShadeController; +import com.android.systemui.shade.ShadeExpandsOnStatusBarLongPress; import com.android.systemui.shade.ShadeExpansionChangeEvent; import com.android.systemui.shade.ShadeExpansionListener; import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.shade.ShadeLogger; import com.android.systemui.shade.ShadeSurface; import com.android.systemui.shade.ShadeViewController; +import com.android.systemui.shade.StatusBarLongPressGestureDetector; import com.android.systemui.shared.recents.utilities.Utilities; import com.android.systemui.shared.statusbar.phone.BarTransitions; import com.android.systemui.statusbar.AutoHideUiElement; @@ -366,6 +368,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { private PhoneStatusBarViewController mPhoneStatusBarViewController; private PhoneStatusBarTransitions mStatusBarTransitions; + private final Provider<StatusBarLongPressGestureDetector> mStatusBarLongPressGestureDetector; private final AuthRippleController mAuthRippleController; @WindowVisibleState private int mStatusBarWindowState = WINDOW_STATE_SHOWING; private final NotificationShadeWindowController mNotificationShadeWindowController; @@ -671,6 +674,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { ShadeController shadeController, WindowRootViewVisibilityInteractor windowRootViewVisibilityInteractor, StatusBarKeyguardViewManager statusBarKeyguardViewManager, + Provider<StatusBarLongPressGestureDetector> statusBarLongPressGestureDetector, ViewMediatorCallback viewMediatorCallback, InitController initController, @Named(TIME_TICK_HANDLER_NAME) Handler timeTickHandler, @@ -778,6 +782,7 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mShadeController = shadeController; mWindowRootViewVisibilityInteractor = windowRootViewVisibilityInteractor; mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; + mStatusBarLongPressGestureDetector = statusBarLongPressGestureDetector; mKeyguardViewMediatorCallback = viewMediatorCallback; mInitController = initController; mPluginDependencyProvider = pluginDependencyProvider; @@ -1527,6 +1532,11 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { // to touch outside the customizer to close it, such as on the status or nav bar. mShadeController.onStatusBarTouch(event); } + if (ShadeExpandsOnStatusBarLongPress.isEnabled() + && mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { + mStatusBarLongPressGestureDetector.get().handleTouch(event); + } + return getNotificationShadeWindowView().onTouchEvent(event); }; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 91c43ddf1ce4..176dd8de6cd4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -39,8 +39,8 @@ import com.android.systemui.Dependency; import com.android.systemui.Flags; import com.android.systemui.Gefingerpoken; import com.android.systemui.res.R; -import com.android.systemui.shade.LongPressGestureDetector; import com.android.systemui.shade.ShadeExpandsOnStatusBarLongPress; +import com.android.systemui.shade.StatusBarLongPressGestureDetector; import com.android.systemui.statusbar.phone.userswitcher.StatusBarUserSwitcherContainer; import com.android.systemui.statusbar.window.StatusBarWindowControllerStore; import com.android.systemui.user.ui.binder.StatusBarUserChipViewBinder; @@ -69,7 +69,7 @@ public class PhoneStatusBarView extends FrameLayout { private InsetsFetcher mInsetsFetcher; private int mDensity; private float mFontScale; - private LongPressGestureDetector mLongPressGestureDetector; + private StatusBarLongPressGestureDetector mStatusBarLongPressGestureDetector; /** * Draw this many pixels into the left/right side of the cutout to optimally use the space @@ -81,9 +81,10 @@ public class PhoneStatusBarView extends FrameLayout { mStatusBarWindowControllerStore = Dependency.get(StatusBarWindowControllerStore.class); } - void setLongPressGestureDetector(LongPressGestureDetector longPressGestureDetector) { + void setLongPressGestureDetector( + StatusBarLongPressGestureDetector statusBarLongPressGestureDetector) { if (ShadeExpandsOnStatusBarLongPress.isEnabled()) { - mLongPressGestureDetector = longPressGestureDetector; + mStatusBarLongPressGestureDetector = statusBarLongPressGestureDetector; } } @@ -207,8 +208,9 @@ public class PhoneStatusBarView extends FrameLayout { @Override public boolean onTouchEvent(MotionEvent event) { - if (ShadeExpandsOnStatusBarLongPress.isEnabled() && mLongPressGestureDetector != null) { - mLongPressGestureDetector.handleTouch(event); + if (ShadeExpandsOnStatusBarLongPress.isEnabled() + && mStatusBarLongPressGestureDetector != null) { + mStatusBarLongPressGestureDetector.handleTouch(event); } if (mTouchEventHandler == null) { Log.w( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt index a94db490df0c..16e023ce17fd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt @@ -34,11 +34,11 @@ import com.android.systemui.plugins.DarkIconDispatcher import com.android.systemui.res.R import com.android.systemui.scene.shared.flag.SceneContainerFlag import com.android.systemui.scene.ui.view.WindowRootView -import com.android.systemui.shade.LongPressGestureDetector import com.android.systemui.shade.ShadeController import com.android.systemui.shade.ShadeExpandsOnStatusBarLongPress import com.android.systemui.shade.ShadeLogger import com.android.systemui.shade.ShadeViewController +import com.android.systemui.shade.StatusBarLongPressGestureDetector import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore @@ -69,7 +69,7 @@ private constructor( private val shadeController: ShadeController, private val shadeViewController: ShadeViewController, private val panelExpansionInteractor: PanelExpansionInteractor, - private val longPressGestureDetector: Provider<LongPressGestureDetector>, + private val statusBarLongPressGestureDetector: Provider<StatusBarLongPressGestureDetector>, private val windowRootView: Provider<WindowRootView>, private val shadeLogger: ShadeLogger, private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?, @@ -119,7 +119,7 @@ private constructor( addCursorSupportToIconContainers() if (ShadeExpandsOnStatusBarLongPress.isEnabled) { - mView.setLongPressGestureDetector(longPressGestureDetector.get()) + mView.setLongPressGestureDetector(statusBarLongPressGestureDetector.get()) } progressProvider?.setReadyToHandleTransition(true) @@ -336,7 +336,7 @@ private constructor( private val shadeController: ShadeController, private val shadeViewController: ShadeViewController, private val panelExpansionInteractor: PanelExpansionInteractor, - private val longPressGestureDetector: Provider<LongPressGestureDetector>, + private val statusBarLongPressGestureDetector: Provider<StatusBarLongPressGestureDetector>, private val windowRootView: Provider<WindowRootView>, private val shadeLogger: ShadeLogger, private val viewUtil: ViewUtil, @@ -361,7 +361,7 @@ private constructor( shadeController, shadeViewController, panelExpansionInteractor, - longPressGestureDetector, + statusBarLongPressGestureDetector, windowRootView, shadeLogger, statusBarMoveFromCenterAnimationController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt index 13ac321473f4..f3d513940bcf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/satellite/ui/viewmodel/DeviceBasedSatelliteViewModel.kt @@ -113,34 +113,38 @@ constructor( } private val showIcon = - canShowIcon - .flatMapLatest { canShow -> - if (!canShow) { - flowOf(false) - } else { - combine( - shouldShowIconForOosAfterHysteresis, - interactor.connectionState, - interactor.isWifiActive, - airplaneModeRepository.isAirplaneMode, - ) { showForOos, connectionState, isWifiActive, isAirplaneMode -> - if (isWifiActive || isAirplaneMode) { - false - } else { - showForOos || - connectionState == SatelliteConnectionState.On || - connectionState == SatelliteConnectionState.Connected + if (interactor.isOpportunisticSatelliteIconEnabled) { + canShowIcon + .flatMapLatest { canShow -> + if (!canShow) { + flowOf(false) + } else { + combine( + shouldShowIconForOosAfterHysteresis, + interactor.connectionState, + interactor.isWifiActive, + airplaneModeRepository.isAirplaneMode, + ) { showForOos, connectionState, isWifiActive, isAirplaneMode -> + if (isWifiActive || isAirplaneMode) { + false + } else { + showForOos || + connectionState == SatelliteConnectionState.On || + connectionState == SatelliteConnectionState.Connected + } } } } + .distinctUntilChanged() + .logDiffsForTable( + tableLog, + columnPrefix = "vm", + columnName = COL_VISIBLE, + initialValue = false, + ) + } else { + flowOf(false) } - .distinctUntilChanged() - .logDiffsForTable( - tableLog, - columnPrefix = "vm", - columnName = COL_VISIBLE, - initialValue = false, - ) .stateIn(scope, SharingStarted.WhileSubscribed(), false) override val icon: StateFlow<Icon?> = diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt index 9164da721e3a..b2a0272c06d1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt @@ -17,7 +17,7 @@ package com.android.systemui.statusbar.pipeline.shared.domain.interactor import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository +import com.android.systemui.statusbar.disableflags.domain.interactor.DisableFlagsInteractor import com.android.systemui.statusbar.pipeline.shared.domain.model.StatusBarDisableFlagsVisibilityModel import javax.inject.Inject import kotlinx.coroutines.flow.Flow @@ -30,13 +30,13 @@ import kotlinx.coroutines.flow.map @SysUISingleton class CollapsedStatusBarInteractor @Inject -constructor(disableFlagsRepository: DisableFlagsRepository) { +constructor(DisableFlagsInteractor: DisableFlagsInteractor) { /** * The visibilities of various status bar child views, based only on the information we received * from disable flags. */ val visibilityViaDisableFlags: Flow<StatusBarDisableFlagsVisibilityModel> = - disableFlagsRepository.disableFlags.map { + DisableFlagsInteractor.disableFlags.map { StatusBarDisableFlagsVisibilityModel( isClockAllowed = it.isClockEnabled, areNotificationIconsAllowed = it.areNotificationIconsEnabled, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt index c7b6be3fc4ac..a72c83e9579c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/prod/WifiRepositoryImpl.kt @@ -92,8 +92,7 @@ constructor( private var wifiPickerTracker: WifiPickerTracker? = null - @VisibleForTesting - val selectedUserContext: Flow<Context> = + private val selectedUserContext: Flow<Context> = userRepository.selectedUserInfo.map { applicationContext.createContextAsUser(UserHandle.of(it.id), /* flags= */ 0) } @@ -112,8 +111,7 @@ constructor( selectedUserContext .flatMapLatest { currentContext -> // flatMapLatest because when selectedUserContext emits a new value, we want - // to - // re-create a whole flow + // to re-create a whole flow callbackFlow { val callback = object : WifiPickerTracker.WifiPickerTrackerCallback { @@ -132,20 +130,16 @@ constructor( .map { it.toWifiNetworkModel() } // [WifiPickerTracker.connectedWifiEntry] will return the - // same - // instance but with updated internals. For example, when - // its - // validation status changes from false to true, the same - // instance is re-used but with the validated field updated. + // same instance but with updated internals. For example, + // when its validation status changes from false to true, + // the same instance is re-used but with the validated + // field updated. // // Because it's the same instance, the flow won't re-emit - // the - // value (even though the internals have changed). So, we - // need - // to transform it into our internal model immediately. - // [toWifiNetworkModel] always returns a new instance, so - // the - // flow is guaranteed to emit. + // the value (even though the internals have changed). So, + // we need to transform it into our internal model + // immediately. [toWifiNetworkModel] always returns a new + // instance, so the flow is guaranteed to emit. send( newPrimaryNetwork = connectedEntry?.toPrimaryWifiNetworkModel() @@ -235,20 +229,15 @@ constructor( .map { it.toWifiNetworkModel() } // [WifiPickerTracker.connectedWifiEntry] will return the same - // instance - // but with updated internals. For example, when its validation - // status - // changes from false to true, the same instance is re-used but - // with the - // validated field updated. + // instance but with updated internals. For example, when its + // validation status changes from false to true, the same + // instance is re-used but with the validated field updated. // // Because it's the same instance, the flow won't re-emit the - // value - // (even though the internals have changed). So, we need to - // transform it - // into our internal model immediately. [toWifiNetworkModel] - // always - // returns a new instance, so the flow is guaranteed to emit. + // value (even though the internals have changed). So, we need + // to transform it into our internal model immediately. + // [toWifiNetworkModel] always returns a new instance, so the + // flow is guaranteed to emit. send( newPrimaryNetwork = connectedEntry?.toPrimaryWifiNetworkModel() @@ -292,12 +281,10 @@ constructor( .create(applicationContext, lifecycle, callback, "WifiRepository") .apply { // By default, [WifiPickerTracker] will scan to see all - // available wifi - // networks in the area. Because SysUI only needs to display the - // **connected** network, we don't need scans to be running (and - // in fact, - // running scans is costly and should be avoided whenever - // possible). + // available wifi networks in the area. Because SysUI only + // needs to display the **connected** network, we don't + // need scans to be running (and in fact, running scans is + // costly and should be avoided whenever possible). this?.disableScanning() } // The lifecycle must be STARTED in order for the callback to receive @@ -382,16 +369,11 @@ constructor( private fun MergedCarrierEntry.convertCarrierMergedToModel(): WifiNetworkModel { // WifiEntry instance values aren't guaranteed to be stable between method calls - // because - // WifiPickerTracker is continuously updating the same object. Save the level in a - // local - // variable so that checking the level validity here guarantees that the level will - // still be - // valid when we create the `WifiNetworkModel.Active` instance later. Otherwise, the - // level - // could be valid here but become invalid later, and `WifiNetworkModel.Active` will - // throw - // an exception. See b/362384551. + // because WifiPickerTracker is continuously updating the same object. Save the + // level in a local variable so that checking the level validity here guarantees + // that the level will still be valid when we create the `WifiNetworkModel.Active` + // instance later. Otherwise, the level could be valid here but become invalid + // later, and `WifiNetworkModel.Active` will throw an exception. See b/362384551. return WifiNetworkModel.CarrierMerged.of( subscriptionId = this.subscriptionId, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt index 584cd3b00a57..1e043ec48142 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowController.kt @@ -36,6 +36,9 @@ interface StatusBarWindowController { /** Adds the status bar view to the window manager. */ fun attach() + /** Called when work should stop and resources should be released. */ + fun stop() + /** Adds the given view to the status bar window view. */ fun addViewToWindow(view: View, layoutParams: ViewGroup.LayoutParams) @@ -78,7 +81,7 @@ interface StatusBarWindowController { */ fun setOngoingProcessRequiresStatusBarVisible(visible: Boolean) - interface Factory { + fun interface Factory { fun create( context: Context, viewCaptureAwareWindowManager: ViewCaptureAwareWindowManager, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java index 6953bbf735f1..811a2ec44ccc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java @@ -51,10 +51,12 @@ import com.android.app.viewcapture.ViewCaptureAwareWindowManager; import com.android.internal.policy.SystemBarUtils; import com.android.systemui.animation.ActivityTransitionAnimator; import com.android.systemui.animation.DelegateTransitionAnimatorController; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentService; import com.android.systemui.res.R; import com.android.systemui.statusbar.core.StatusBarConnectedDisplays; +import com.android.systemui.statusbar.core.StatusBarRootModernization; import com.android.systemui.statusbar.data.repository.StatusBarConfigurationController; import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider; import com.android.systemui.statusbar.window.StatusBarWindowModule.InternalWindowViewInflater; @@ -66,6 +68,7 @@ import dagger.assisted.AssistedFactory; import dagger.assisted.AssistedInject; import java.util.Optional; +import java.util.concurrent.Executor; /** * Encapsulates all logic for the status bar window state management. @@ -79,6 +82,7 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController private final StatusBarConfigurationController mStatusBarConfigurationController; private final IWindowManager mIWindowManager; private final StatusBarContentInsetsProvider mContentInsetsProvider; + private final Executor mMainExecutor; private int mBarHeight = -1; private final State mCurrentState = new State(); private boolean mIsAttached; @@ -101,12 +105,14 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController IWindowManager iWindowManager, @Assisted StatusBarContentInsetsProvider contentInsetsProvider, FragmentService fragmentService, - Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider) { + Optional<UnfoldTransitionProgressProvider> unfoldTransitionProgressProvider, + @Main Executor mainExecutor) { mContext = context; mWindowManager = viewCaptureAwareWindowManager; mStatusBarConfigurationController = statusBarConfigurationController; mIWindowManager = iWindowManager; mContentInsetsProvider = contentInsetsProvider; + mMainExecutor = mainExecutor; mStatusBarWindowView = statusBarWindowViewInflater.inflate(context); mFragmentService = fragmentService; mLaunchAnimationContainer = mStatusBarWindowView.findViewById( @@ -167,6 +173,19 @@ public class StatusBarWindowControllerImpl implements StatusBarWindowController } @Override + public void stop() { + StatusBarConnectedDisplays.assertInNewMode(); + + mWindowManager.removeView(mStatusBarWindowView); + + if (StatusBarRootModernization.isEnabled()) { + return; + } + // Fragment transactions need to happen on the main thread. + mMainExecutor.execute(() -> mFragmentService.removeAndDestroy(mStatusBarWindowView)); + } + + @Override public void addViewToWindow(@NonNull View view, @NonNull ViewGroup.LayoutParams layoutParams) { mStatusBarWindowView.addView(view, layoutParams); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt index 051d463a8b97..74031612f28e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt @@ -70,6 +70,10 @@ constructor( ) } + override suspend fun onDisplayRemovalAction(instance: StatusBarWindowController) { + instance.stop() + } + override val instanceClass = StatusBarWindowController::class.java } diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java index d97cae2a99e3..d367455d26c7 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java +++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java @@ -50,6 +50,7 @@ import com.android.systemui.plugins.ToastPlugin; public class SystemUIToast implements ToastPlugin.Toast { static final String TAG = "SystemUIToast"; final Context mContext; + final Context mDisplayContext; final CharSequence mText; final ToastPlugin.Toast mPluginToast; @@ -68,17 +69,18 @@ public class SystemUIToast implements ToastPlugin.Toast { @Nullable private final Animator mInAnimator; @Nullable private final Animator mOutAnimator; - SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text, - String packageName, int userId, int orientation) { - this(layoutInflater, context, text, null, packageName, userId, + SystemUIToast(LayoutInflater layoutInflater, Context applicationContext, Context displayContext, + CharSequence text, String packageName, int userId, int orientation) { + this(layoutInflater, applicationContext, displayContext, text, null, packageName, userId, orientation); } - SystemUIToast(LayoutInflater layoutInflater, Context context, CharSequence text, - ToastPlugin.Toast pluginToast, String packageName, @UserIdInt int userId, - int orientation) { + SystemUIToast(LayoutInflater layoutInflater, Context applicationContext, Context displayContext, + CharSequence text, ToastPlugin.Toast pluginToast, String packageName, + @UserIdInt int userId, int orientation) { mLayoutInflater = layoutInflater; - mContext = context; + mContext = applicationContext; + mDisplayContext = displayContext; mText = text; mPluginToast = pluginToast; mPackageName = packageName; @@ -221,9 +223,9 @@ public class SystemUIToast implements ToastPlugin.Toast { mPluginToast.onOrientationChange(orientation); } - mDefaultY = mContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset); + mDefaultY = mDisplayContext.getResources().getDimensionPixelSize(R.dimen.toast_y_offset); mDefaultGravity = - mContext.getResources().getInteger(R.integer.config_toastDefaultGravity); + mDisplayContext.getResources().getInteger(R.integer.config_toastDefaultGravity); } private Animator createInAnimator() { diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java index 9ae66749aa0a..388d4bd6780b 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java +++ b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java @@ -65,15 +65,16 @@ public class ToastFactory implements Dumpable { /** * Create a toast to be shown by ToastUI. */ - public SystemUIToast createToast(Context context, CharSequence text, String packageName, - int userId, int orientation) { - LayoutInflater layoutInflater = LayoutInflater.from(context); + public SystemUIToast createToast(Context applicationContext, Context displayContext, + CharSequence text, String packageName, int userId, int orientation) { + LayoutInflater layoutInflater = LayoutInflater.from(displayContext); if (isPluginAvailable()) { - return new SystemUIToast(layoutInflater, context, text, mPlugin.createToast(text, - packageName, userId), packageName, userId, orientation); + return new SystemUIToast(layoutInflater, applicationContext, displayContext, text, + mPlugin.createToast(text, packageName, userId), packageName, userId, + orientation); } - return new SystemUIToast(layoutInflater, context, text, packageName, userId, - orientation); + return new SystemUIToast(layoutInflater, applicationContext, displayContext, text, + packageName, userId, orientation); } private boolean isPluginAvailable() { diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java index 32a4f12777ac..12f73b8a887d 100644 --- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java +++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java @@ -135,8 +135,8 @@ public class ToastUI implements return; } Context displayContext = context.createDisplayContext(display); - mToast = mToastFactory.createToast(displayContext /* sysuiContext */, text, packageName, - userHandle.getIdentifier(), mOrientation); + mToast = mToastFactory.createToast(mContext, displayContext /* sysuiContext */, text, + packageName, userHandle.getIdentifier(), mOrientation); if (mToast.getInAnimation() != null) { mToast.getInAnimation().start(); diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt index 2a9b1b97b48f..e5c1e7daa25a 100644 --- a/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt +++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/SysUICoroutinesModule.kt @@ -17,14 +17,16 @@ package com.android.systemui.util.kotlin import android.os.Handler +import com.android.systemui.coroutines.newTracingContext import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background -import com.android.systemui.dagger.qualifiers.Tracing import com.android.systemui.dagger.qualifiers.UiBackground import com.android.systemui.util.settings.SettingsSingleThreadBackground import dagger.Module import dagger.Provides +import java.util.concurrent.Executor +import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.DelicateCoroutinesApi @@ -33,8 +35,6 @@ import kotlinx.coroutines.android.asCoroutineDispatcher import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.newFixedThreadPoolContext import kotlinx.coroutines.plus -import java.util.concurrent.Executor -import kotlin.coroutines.CoroutineContext private const val LIMIT_BACKGROUND_DISPATCHER_THREADS = true @@ -62,7 +62,7 @@ class SysUICoroutinesModule { @Background @Deprecated( "Use @Background CoroutineContext instead", - ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext") + ReplaceWith("bgCoroutineContext()", "kotlin.coroutines.CoroutineContext"), ) fun bgDispatcher(): CoroutineDispatcher { return if (LIMIT_BACKGROUND_DISPATCHER_THREADS) { @@ -73,7 +73,7 @@ class SysUICoroutinesModule { // code on those. newFixedThreadPoolContext( nThreads = Runtime.getRuntime().availableProcessors(), - name = "SystemUIBg" + name = "SystemUIBg", ) } else { Dispatchers.IO @@ -89,10 +89,17 @@ class SysUICoroutinesModule { } @Provides + @SysUISingleton + @SettingsSingleThreadBackground + fun settingsScope(@Background bgDispatcher: CoroutineDispatcher): CoroutineScope { + return CoroutineScope(bgDispatcher + newTracingContext("SettingsProxy")) + } + + @Provides @Background @SysUISingleton fun bgCoroutineContext( - @Background bgCoroutineDispatcher: CoroutineDispatcher, + @Background bgCoroutineDispatcher: CoroutineDispatcher ): CoroutineContext { return bgCoroutineDispatcher } @@ -103,7 +110,7 @@ class SysUICoroutinesModule { @UiBackground @Deprecated( "Use @UiBackground CoroutineContext instead", - ReplaceWith("uiBgCoroutineContext()", "kotlin.coroutines.CoroutineContext") + ReplaceWith("uiBgCoroutineContext()", "kotlin.coroutines.CoroutineContext"), ) fun uiBgDispatcher(@UiBackground uiBgExecutor: Executor): CoroutineDispatcher = uiBgExecutor.asCoroutineDispatcher() @@ -112,7 +119,7 @@ class SysUICoroutinesModule { @UiBackground @SysUISingleton fun uiBgCoroutineContext( - @UiBackground uiBgCoroutineDispatcher: CoroutineDispatcher, + @UiBackground uiBgCoroutineDispatcher: CoroutineDispatcher ): CoroutineContext { return uiBgCoroutineDispatcher } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt index 6816d35f7699..c4b028d7d98b 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ringer/ui/binder/VolumeDialogRingerViewBinder.kt @@ -49,7 +49,7 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact val drawerContainer = requireViewById<View>(R.id.volume_drawer_container) val selectedButtonView = requireViewById<ImageButton>(R.id.volume_new_ringer_active_button) - val volumeDialogView = requireViewById<ViewGroup>(R.id.volume_dialog) + val volumeDialogBackgroundView = requireViewById<View>(R.id.volume_dialog_background) repeatWhenAttached { viewModel( traceName = "VolumeDialogRingerViewBinder", @@ -71,19 +71,17 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact is RingerDrawerState.Initial -> { drawerContainer.visibility = View.GONE selectedButtonView.visibility = View.VISIBLE - volumeDialogView.setBackgroundResource( + volumeDialogBackgroundView.setBackgroundResource( R.drawable.volume_dialog_background ) } - is RingerDrawerState.Closed -> { drawerContainer.visibility = View.GONE selectedButtonView.visibility = View.VISIBLE - volumeDialogView.setBackgroundResource( + volumeDialogBackgroundView.setBackgroundResource( R.drawable.volume_dialog_background ) } - is RingerDrawerState.Open -> { drawerContainer.visibility = View.VISIBLE selectedButtonView.visibility = View.GONE @@ -91,17 +89,16 @@ constructor(private val viewModelFactory: VolumeDialogRingerDrawerViewModel.Fact uiModel.currentButtonIndex != uiModel.availableButtons.size - 1 ) { - volumeDialogView.setBackgroundResource( + volumeDialogBackgroundView.setBackgroundResource( R.drawable.volume_dialog_background_small_radius ) } } } } - is RingerViewModelState.Unavailable -> { drawerAndRingerContainer.visibility = View.GONE - volumeDialogView.setBackgroundResource( + volumeDialogBackgroundView.setBackgroundResource( R.drawable.volume_dialog_background ) } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt index a17c1e541b5e..9078f82d3e98 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/ui/VolumeDialogSlidersViewBinder.kt @@ -38,9 +38,10 @@ constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory) fun bind(view: View) { with(view) { - val volumeDialog: View = requireViewById(R.id.volume_dialog) val floatingSlidersContainer: ViewGroup = requireViewById(R.id.volume_dialog_floating_sliders_container) + val mainSliderContainer: View = + requireViewById(R.id.volume_dialog_main_slider_container) repeatWhenAttached { viewModel( traceName = "VolumeDialogSlidersViewBinder", @@ -49,7 +50,7 @@ constructor(private val viewModelFactory: VolumeDialogSlidersViewModel.Factory) ) { viewModel -> viewModel.sliders .onEach { uiModel -> - uiModel.sliderComponent.sliderViewBinder().bind(volumeDialog) + uiModel.sliderComponent.sliderViewBinder().bind(mainSliderContainer) val floatingSliderViewBinders = uiModel.floatingSliderComponent floatingSlidersContainer.ensureChildCount( diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt index d9a945cfedfd..f6c1743a4bea 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt @@ -19,13 +19,11 @@ package com.android.systemui.volume.dialog.ui.binder import android.app.Dialog import android.graphics.Rect import android.graphics.Region -import android.view.Gravity import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver import android.view.ViewTreeObserver.InternalInsetsInfo -import android.widget.FrameLayout -import androidx.annotation.GravityInt +import androidx.constraintlayout.motion.widget.MotionLayout import com.android.internal.view.RotationPolicy import com.android.systemui.lifecycle.WindowLifecycleState import com.android.systemui.lifecycle.repeatWhenAttached @@ -41,7 +39,6 @@ import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSlidersViewBind import com.android.systemui.volume.dialog.ui.VolumeDialogResources import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory import com.android.systemui.volume.dialog.ui.utils.suspendAnimate -import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogGravityViewModel import com.android.systemui.volume.dialog.ui.viewmodel.VolumeDialogViewModel import com.android.systemui.volume.dialog.utils.VolumeTracer import javax.inject.Inject @@ -53,6 +50,7 @@ import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.mapLatest import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.scan import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine @@ -63,7 +61,6 @@ class VolumeDialogViewBinder @Inject constructor( private val volumeResources: VolumeDialogResources, - private val gravityViewModel: VolumeDialogGravityViewModel, private val dialogViewModelFactory: VolumeDialogViewModel.Factory, private val jankListenerFactory: JankListenerFactory, private val tracer: VolumeTracer, @@ -74,21 +71,23 @@ constructor( fun bind(dialog: Dialog) { // Root view of the Volume Dialog. - val root: ViewGroup = dialog.requireViewById(R.id.volume_dialog_root) - // Volume Dialog container view that contains the dialog itself without the floating sliders - val container: View = root.requireViewById(R.id.volume_dialog_container) - container.alpha = 0f - container.repeatWhenAttached { + val root: MotionLayout = dialog.requireViewById(R.id.volume_dialog_root) + root.alpha = 0f + root.repeatWhenAttached { root.viewModel( traceName = "VolumeDialogViewBinder", minWindowLifecycleState = WindowLifecycleState.ATTACHED, factory = { dialogViewModelFactory.create() }, ) { viewModel -> - animateVisibility(container, dialog, viewModel.dialogVisibilityModel) + animateVisibility(root, dialog, viewModel.dialogVisibilityModel) viewModel.dialogTitle.onEach { dialog.window?.setTitle(it) }.launchIn(this) - gravityViewModel.dialogGravity - .onEach { container.setLayoutGravity(it) } + viewModel.motionState + .scan(0) { acc, motionState -> + // don't animate the initial state + root.transitionToState(motionState, animate = acc != 0) + acc + 1 + } .launchIn(this) launch { root.viewTreeObserver.computeInternalInsetsListener(root) } @@ -130,15 +129,13 @@ constructor( .launchIn(this) } - private suspend fun calculateTranslationX(view: View): Float? { + private fun calculateTranslationX(view: View): Float? { return if (view.display.rotation == RotationPolicy.NATURAL_ROTATION) { - val dialogGravity = gravityViewModel.dialogGravity.first() - val isGravityLeft = (dialogGravity and Gravity.LEFT) == Gravity.LEFT - if (isGravityLeft) { + if (view.isLayoutRtl) { -1 } else { 1 - } * view.width / 2.0f + } * view.width / 2f } else { null } @@ -211,10 +208,11 @@ constructor( getBoundsInWindow(boundsRect, false) } - private fun View.setLayoutGravity(@GravityInt newGravity: Int) { - val frameLayoutParams = - layoutParams as? FrameLayout.LayoutParams - ?: error("View must be a child of a FrameLayout") - layoutParams = frameLayoutParams.apply { gravity = newGravity } + private fun MotionLayout.transitionToState(newState: Int, animate: Boolean) { + if (animate) { + transitionToState(newState) + } else { + jumpToState(newState) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt deleted file mode 100644 index 112afb1debf5..000000000000 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogGravityViewModel.kt +++ /dev/null @@ -1,93 +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.dialog.ui.viewmodel - -import android.content.Context -import android.content.res.Configuration -import android.view.Gravity -import androidx.annotation.GravityInt -import com.android.systemui.dagger.qualifiers.Application -import com.android.systemui.dagger.qualifiers.UiBackground -import com.android.systemui.res.R -import com.android.systemui.statusbar.policy.ConfigurationController -import com.android.systemui.statusbar.policy.DevicePostureController -import com.android.systemui.statusbar.policy.devicePosture -import com.android.systemui.statusbar.policy.onConfigChanged -import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog -import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope -import javax.inject.Inject -import kotlin.coroutines.CoroutineContext -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.withContext - -/** Exposes dialog [GravityInt] for use in the UI layer. */ -@VolumeDialogScope -class VolumeDialogGravityViewModel -@Inject -constructor( - @Application private val context: Context, - @VolumeDialog private val coroutineScope: CoroutineScope, - @UiBackground private val uiBackgroundCoroutineContext: CoroutineContext, - configurationController: ConfigurationController, - private val devicePostureController: DevicePostureController, -) { - - @GravityInt private var originalGravity: Int = context.getAbsoluteGravity() - - val dialogGravity: Flow<Int> = - combine( - devicePostureController.devicePosture(), - configurationController.onConfigChanged.onEach { onConfigurationChanged() }, - ) { devicePosture, configuration -> - context.calculateGravity(devicePosture, configuration) - } - .stateIn( - scope = coroutineScope, - started = SharingStarted.Eagerly, - context.calculateGravity(), - ) - - private suspend fun onConfigurationChanged() { - withContext(uiBackgroundCoroutineContext) { originalGravity = context.getAbsoluteGravity() } - } - - @GravityInt - private fun Context.calculateGravity( - devicePosture: Int = devicePostureController.devicePosture, - config: Configuration = resources.configuration, - ): Int { - val isLandscape = config.orientation == Configuration.ORIENTATION_LANDSCAPE - val isHalfOpen = devicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED - val gravity = - if (isLandscape && isHalfOpen) { - originalGravity or Gravity.TOP - } else { - originalGravity - } - return getAbsoluteGravity(gravity) - } -} - -@GravityInt -private fun Context.getAbsoluteGravity( - gravity: Int = resources.getInteger(R.integer.volume_dialog_gravity) -): Int = with(resources) { Gravity.getAbsoluteGravity(gravity, configuration.layoutDirection) } diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt index 869a6a2e87d5..0352799916bc 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/viewmodel/VolumeDialogViewModel.kt @@ -17,7 +17,12 @@ package com.android.systemui.volume.dialog.ui.viewmodel import android.content.Context +import android.content.res.Configuration import com.android.systemui.res.R +import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.DevicePostureController +import com.android.systemui.statusbar.policy.devicePosture +import com.android.systemui.statusbar.policy.onConfigChanged import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogStateInteractor import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor import com.android.systemui.volume.dialog.shared.model.VolumeDialogStateModel @@ -32,6 +37,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart /** Provides a state for the Volume Dialog. */ @OptIn(ExperimentalCoroutinesApi::class) @@ -42,8 +48,23 @@ constructor( dialogVisibilityInteractor: VolumeDialogVisibilityInteractor, volumeDialogSlidersInteractor: VolumeDialogSlidersInteractor, volumeDialogStateInteractor: VolumeDialogStateInteractor, + devicePostureController: DevicePostureController, + configurationController: ConfigurationController, ) { + val motionState: Flow<Int> = + combine( + devicePostureController.devicePosture(), + configurationController.onConfigChanged.onStart { + emit(context.resources.configuration) + }, + ) { devicePosture, configuration -> + if (shouldOffsetVolumeDialog(devicePosture, configuration)) { + R.id.volume_dialog_half_folded_constraint_set + } else { + R.id.volume_dialog_constraint_set + } + } val dialogVisibilityModel: Flow<VolumeDialogVisibilityModel> = dialogVisibilityInteractor.dialogVisibility val dialogTitle: Flow<String> = @@ -57,6 +78,13 @@ constructor( } .filterNotNull() + /** @return true when the foldable device screen curve is in the way of the volume dialog */ + private fun shouldOffsetVolumeDialog(devicePosture: Int, config: Configuration): Boolean { + val isLandscape = config.orientation == Configuration.ORIENTATION_LANDSCAPE + val isHalfOpen = devicePosture == DevicePostureController.DEVICE_POSTURE_HALF_OPENED + return isLandscape && isHalfOpen + } + @AssistedFactory interface Factory { fun create(): VolumeDialogViewModel diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt index 65b62737b692..2aa6e7b18154 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/keyguard/ClockEventControllerTest.kt @@ -105,8 +105,7 @@ class ClockEventControllerTest : SysuiTestCase() { private val mainExecutor = ImmediateExecutor() private lateinit var repository: FakeKeyguardRepository - private val messageBuffer = LogcatOnlyMessageBuffer(LogLevel.DEBUG) - private val clockBuffers = ClockMessageBuffers(messageBuffer, messageBuffer, messageBuffer) + private val clockBuffers = ClockMessageBuffers(LogcatOnlyMessageBuffer(LogLevel.DEBUG)) private lateinit var underTest: ClockEventController @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher 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 a940bc9b3e20..425aad2bd43c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityTransitionAnimatorTest.kt @@ -16,10 +16,12 @@ import android.view.RemoteAnimationAdapter import android.view.RemoteAnimationTarget import android.view.SurfaceControl import android.view.ViewGroup +import android.view.WindowManager.TRANSIT_NONE import android.widget.FrameLayout import android.widget.LinearLayout import android.window.RemoteTransition import android.window.TransitionFilter +import android.window.WindowAnimationState import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase @@ -34,6 +36,10 @@ import junit.framework.Assert.assertTrue import junit.framework.AssertionFailedError import kotlin.concurrent.thread import kotlin.test.assertEquals +import kotlin.time.Duration.Companion.seconds +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout import org.junit.After import org.junit.Assert.assertThrows import org.junit.Before @@ -258,7 +264,6 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @DisableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) @Test fun doesNotRegisterLongLivedTransitionIfFlagIsDisabled() { - val controller = object : DelegateTransitionAnimatorController(controller) { override val transitionCookie = @@ -273,7 +278,6 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @EnableFlags(Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED) @Test fun doesNotRegisterLongLivedTransitionIfMissingRequiredProperties() { - // No TransitionCookie val controllerWithoutCookie = object : DelegateTransitionAnimatorController(controller) { @@ -348,7 +352,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { fun doesNotStartIfAnimationIsCancelled() { val runner = activityTransitionAnimator.createRunner(controller) runner.onAnimationCancelled() - runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback) + runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback) waitForIdleSync() verify(controller).onTransitionAnimationCancelled() @@ -361,7 +365,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun cancelsIfNoOpeningWindowIsFound() { val runner = activityTransitionAnimator.createRunner(controller) - runner.onAnimationStart(0, emptyArray(), emptyArray(), emptyArray(), iCallback) + runner.onAnimationStart(TRANSIT_NONE, emptyArray(), emptyArray(), emptyArray(), iCallback) waitForIdleSync() verify(controller).onTransitionAnimationCancelled() @@ -374,7 +378,13 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { @Test fun startsAnimationIfWindowIsOpening() { val runner = activityTransitionAnimator.createRunner(controller) - runner.onAnimationStart(0, arrayOf(fakeWindow()), emptyArray(), emptyArray(), iCallback) + runner.onAnimationStart( + TRANSIT_NONE, + arrayOf(fakeWindow()), + emptyArray(), + emptyArray(), + iCallback, + ) waitForIdleSync() verify(listener).onTransitionAnimationStart() verify(controller).onTransitionAnimationStart(anyBoolean()) @@ -387,6 +397,113 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { } } + @DisableFlags( + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun creatingRunnerWithLazyInitializationThrows_whenTheFlagsAreDisabled() { + assertThrows(IllegalStateException::class.java) { + activityTransitionAnimator.createRunner(controller, initializeLazily = true) + } + } + + @EnableFlags( + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun runnerCreatesDelegateLazily_whenPostingTimeouts() { + val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true) + assertNull(runner.delegate) + runner.postTimeouts() + assertNotNull(runner.delegate) + } + + @EnableFlags( + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun runnerCreatesDelegateLazily_onAnimationStart() { + val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true) + assertNull(runner.delegate) + + // The delegate is cleaned up after execution (which happens in another thread), so what we + // do instead is check if it becomes non-null at any point with a 1 second timeout. This + // will tell us that takeOverWithAnimation() triggered the lazy initialization. + var delegateInitialized = false + runBlocking { + val initChecker = launch { + withTimeout(1.seconds) { + while (runner.delegate == null) continue + delegateInitialized = true + } + } + runner.onAnimationStart( + TRANSIT_NONE, + arrayOf(fakeWindow()), + emptyArray(), + emptyArray(), + iCallback, + ) + initChecker.join() + } + assertTrue(delegateInitialized) + } + + @EnableFlags( + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun runnerCreatesDelegateLazily_onAnimationTakeover() { + val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = true) + assertNull(runner.delegate) + + // The delegate is cleaned up after execution (which happens in another thread), so what we + // do instead is check if it becomes non-null at any point with a 1 second timeout. This + // will tell us that takeOverWithAnimation() triggered the lazy initialization. + var delegateInitialized = false + runBlocking { + val initChecker = launch { + withTimeout(1.seconds) { + while (runner.delegate == null) continue + delegateInitialized = true + } + } + runner.takeOverAnimation( + arrayOf(fakeWindow()), + arrayOf(WindowAnimationState()), + SurfaceControl.Transaction(), + iCallback, + ) + initChecker.join() + } + assertTrue(delegateInitialized) + } + + @DisableFlags( + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) + @Test + fun animationTakeoverThrows_whenTheFlagsAreDisabled() { + val runner = activityTransitionAnimator.createRunner(controller, initializeLazily = false) + assertThrows(IllegalStateException::class.java) { + runner.takeOverAnimation( + arrayOf(fakeWindow()), + emptyArray(), + SurfaceControl.Transaction(), + iCallback, + ) + } + } + + @DisableFlags( + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LIBRARY, + Flags.FLAG_RETURN_ANIMATION_FRAMEWORK_LONG_LIVED, + ) @Test fun disposeRunner_delegateDereferenced() { val runner = activityTransitionAnimator.createRunner(controller) @@ -409,7 +526,7 @@ class ActivityTransitionAnimatorTest : SysuiTestCase() { false, Rect(), Rect(), - 0, + 1, Point(), Rect(), bounds, diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java index 0b9c06f2dbe2..5ada2f3fd63d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegateControllerTest.java @@ -222,7 +222,7 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { when(SubscriptionManager.getDefaultDataSubscriptionId()).thenReturn(SUB_ID); SubscriptionInfo info = mock(SubscriptionInfo.class); when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(info); - when(mToastFactory.createToast(any(), anyString(), anyString(), anyInt(), anyInt())) + when(mToastFactory.createToast(any(), any(), anyString(), anyString(), anyInt(), anyInt())) .thenReturn(mSystemUIToast); when(mSystemUIToast.getView()).thenReturn(mToastView); when(mSystemUIToast.getGravity()).thenReturn(GRAVITY_FLAGS); @@ -275,8 +275,8 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { mInternetDialogController.connectCarrierNetwork(); verify(mMergedCarrierEntry).connect(null /* callback */, false /* showToast */); - verify(mToastFactory).createToast(any(), eq(TOAST_MESSAGE_STRING), anyString(), anyInt(), - anyInt()); + verify(mToastFactory).createToast(any(), any(), eq(TOAST_MESSAGE_STRING), anyString(), + anyInt(), anyInt()); } @Test @@ -288,7 +288,7 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { mInternetDialogController.connectCarrierNetwork(); verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */); - verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(), + verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(), anyInt()); } @@ -302,7 +302,7 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { mInternetDialogController.connectCarrierNetwork(); verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */); - verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(), + verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(), anyInt()); } @@ -321,7 +321,7 @@ public class InternetDialogDelegateControllerTest extends SysuiTestCase { mInternetDialogController.connectCarrierNetwork(); verify(mMergedCarrierEntry, never()).connect(null /* callback */, false /* showToast */); - verify(mToastFactory, never()).createToast(any(), anyString(), anyString(), anyInt(), + verify(mToastFactory, never()).createToast(any(), any(), anyString(), anyString(), anyInt(), anyInt()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayCoreStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayCoreStartableTest.kt new file mode 100644 index 000000000000..c8faa81adffa --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayCoreStartableTest.kt @@ -0,0 +1,112 @@ +/* + * 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.reardisplay + +import android.hardware.devicestate.feature.flags.Flags.FLAG_DEVICE_STATE_RDM_V2 +import android.hardware.display.rearDisplay +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.view.Display +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.deviceStateManager +import com.android.systemui.display.domain.interactor.RearDisplayStateInteractor +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.testScope +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.rearDisplayInnerDialogDelegateFactory +import com.android.systemui.statusbar.phone.SystemUIDialog +import com.android.systemui.testKosmos +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import org.junit.Before +import org.junit.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +/** atest SystemUITests:com.android.systemui.reardisplay.RearDisplayCoreStartableTest */ +@SmallTest +@kotlinx.coroutines.ExperimentalCoroutinesApi +class RearDisplayCoreStartableTest : SysuiTestCase() { + + private val kosmos = testKosmos().useUnconfinedTestDispatcher() + private val mockDelegate: RearDisplayInnerDialogDelegate = mock() + private val mockDialog: SystemUIDialog = mock() + + private val fakeRearDisplayStateInteractor = FakeRearDisplayStateInteractor(kosmos) + private val impl = + RearDisplayCoreStartable( + mContext, + kosmos.deviceStateManager, + fakeRearDisplayStateInteractor, + kosmos.rearDisplayInnerDialogDelegateFactory, + kosmos.testScope, + ) + + @Before + fun setup() { + whenever(kosmos.rearDisplay.flags).thenReturn(Display.FLAG_REAR) + whenever(kosmos.rearDisplay.displayAdjustments) + .thenReturn(mContext.display.displayAdjustments) + whenever(kosmos.rearDisplayInnerDialogDelegateFactory.create(any(), any())) + .thenReturn(mockDelegate) + whenever(mockDelegate.createDialog()).thenReturn(mockDialog) + } + + @Test + @DisableFlags(FLAG_DEVICE_STATE_RDM_V2) + fun testWhenFlagDisabled() = + kosmos.runTest { + impl.use { + it.start() + assertThat(impl.stateChangeListener).isNull() + } + } + + @Test + @EnableFlags(FLAG_DEVICE_STATE_RDM_V2) + fun testShowAndDismissDialog() = + kosmos.runTest { + impl.use { + it.start() + fakeRearDisplayStateInteractor.emitRearDisplay() + verify(mockDialog).show() + verify(mockDialog, never()).dismiss() + + fakeRearDisplayStateInteractor.emitDisabled() + verify(mockDialog).dismiss() + } + } + + private class FakeRearDisplayStateInteractor(private val kosmos: Kosmos) : + RearDisplayStateInteractor { + private val stateFlow = MutableSharedFlow<RearDisplayStateInteractor.State>() + + suspend fun emitRearDisplay() = + stateFlow.emit(RearDisplayStateInteractor.State.Enabled(kosmos.rearDisplay)) + + suspend fun emitDisabled() = stateFlow.emit(RearDisplayStateInteractor.State.Disabled) + + override val state: Flow<RearDisplayStateInteractor.State> + get() = stateFlow + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.kt new file mode 100644 index 000000000000..60588802ffa9 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayInnerDialogDelegateTest.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.reardisplay + +import android.testing.TestableLooper +import android.view.View +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.res.R +import com.android.systemui.statusbar.phone.systemUIDialogDotFactory +import com.android.systemui.testKosmos +import junit.framework.Assert.assertFalse +import junit.framework.Assert.assertTrue +import org.junit.Test +import org.mockito.Mockito.verify +import org.mockito.kotlin.mock + +/** atest SystemUITests:com.android.systemui.reardisplay.RearDisplayInnerDialogDelegateTest */ +@SmallTest +@TestableLooper.RunWithLooper +class RearDisplayInnerDialogDelegateTest : SysuiTestCase() { + + private val kosmos = testKosmos() + + @Test + fun testShowAndDismissDialog() { + val dialogDelegate = + RearDisplayInnerDialogDelegate(kosmos.systemUIDialogDotFactory, mContext) {} + + val dialog = dialogDelegate.createDialog() + dialog.show() + assertTrue(dialog.isShowing) + + dialog.dismiss() + assertFalse(dialog.isShowing) + } + + @Test + fun testCancel() { + val mockCallback = mock<Runnable>() + RearDisplayInnerDialogDelegate(kosmos.systemUIDialogDotFactory, mContext) { + mockCallback.run() + } + .createDialog() + .apply { + show() + findViewById<View>(R.id.button_cancel).performClick() + verify(mockCallback).run() + } + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt index 8bd8b72e5527..2812bd334b0f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextViewTest.kt @@ -15,11 +15,16 @@ */ package systemui.shared.clocks.view +import android.graphics.Typeface import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.plugins.clocks.ClockMessageBuffers +import com.android.systemui.plugins.clocks.ClockSettings +import com.android.systemui.shared.clocks.ClockContext import com.android.systemui.shared.clocks.FontTextStyle import com.android.systemui.shared.clocks.LogUtil +import com.android.systemui.shared.clocks.TypefaceCache import com.android.systemui.shared.clocks.view.SimpleDigitalClockTextView import org.junit.Assert.assertEquals import org.junit.Before @@ -38,7 +43,23 @@ class SimpleDigitalClockTextViewTest : SysuiTestCase() { @Before fun setup() { - underTest = SimpleDigitalClockTextView(context, messageBuffer) + underTest = + SimpleDigitalClockTextView( + ClockContext( + context, + context.resources, + ClockSettings(), + TypefaceCache(messageBuffer) { + // TODO(b/364680873): Move constant to config_clockFontFamily when shipping + return@TypefaceCache Typeface.create( + "google-sans-flex-clock", + Typeface.NORMAL, + ) + }, + ClockMessageBuffers(messageBuffer), + messageBuffer, + ) + ) underTest.textStyle = FontTextStyle() underTest.aodStyle = FontTextStyle() underTest.text = "0" diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt index a8618eb544d4..3a46d038f946 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt @@ -20,9 +20,8 @@ import com.android.systemui.res.R import com.android.systemui.shade.data.repository.shadeRepository import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor import com.android.systemui.shade.domain.interactor.shadeInteractor -import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel -import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationTestHelper import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout @@ -31,7 +30,6 @@ import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.ScrimController import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController -import com.android.systemui.statusbar.policy.configurationController import com.android.systemui.statusbar.policy.fakeConfigurationController import com.android.systemui.testKosmos import com.android.systemui.util.mockito.any @@ -144,7 +142,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { context = context, configurationController = configurationController, dumpManager = mock(), - splitShadeStateController = ResourcesSplitShadeStateController() + splitShadeStateController = ResourcesSplitShadeStateController(), ), keyguardTransitionControllerFactory = { notificationPanelController -> LockscreenShadeKeyguardTransitionController( @@ -153,7 +151,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { context = context, configurationController = configurationController, dumpManager = mock(), - splitShadeStateController = ResourcesSplitShadeStateController() + splitShadeStateController = ResourcesSplitShadeStateController(), ) }, depthController = depthController, @@ -171,7 +169,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { splitShadeStateController = ResourcesSplitShadeStateController(), shadeLockscreenInteractorLazy = { shadeLockscreenInteractor }, naturalScrollingSettingObserver = naturalScrollingSettingObserver, - lazyQSSceneAdapter = { qsSceneAdapter } + lazyQSSceneAdapter = { qsSceneAdapter }, ) transitionController.addCallback(transitionControllerCallback) @@ -229,7 +227,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { verify(statusbarStateController).setState(StatusBarState.SHADE_LOCKED) assertFalse( "Waking to shade locked when not dozing", - transitionController.isWakingToShadeLocked + transitionController.isWakingToShadeLocked, ) } @@ -247,9 +245,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { fun testDontGoWhenShadeDisabled() = testScope.runTest { disableFlagsRepository.disableFlags.value = - DisableFlagsModel( - disable2 = DISABLE2_NOTIFICATION_SHADE, - ) + DisableFlagsModel(disable2 = DISABLE2_NOTIFICATION_SHADE) testScope.runCurrent() transitionController.goToLockedShade(null) verify(statusbarStateController, never()).setState(anyInt()) @@ -454,7 +450,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { val distance = 10 context.orCreateTestableResources.addOverride( R.dimen.lockscreen_shade_scrim_transition_distance, - distance + distance, ) configurationController.notifyConfigurationChanged() @@ -463,7 +459,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { verify(scrimController) .transitionToFullShadeProgress( progress = eq(0.5f), - lockScreenNotificationsProgress = anyFloat() + lockScreenNotificationsProgress = anyFloat(), ) } @@ -474,11 +470,11 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { val delay = 10 context.orCreateTestableResources.addOverride( R.dimen.lockscreen_shade_notifications_scrim_transition_distance, - distance + distance, ) context.orCreateTestableResources.addOverride( R.dimen.lockscreen_shade_notifications_scrim_transition_delay, - delay + delay, ) configurationController.notifyConfigurationChanged() @@ -487,7 +483,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { verify(scrimController) .transitionToFullShadeProgress( progress = anyFloat(), - lockScreenNotificationsProgress = eq(0.1f) + lockScreenNotificationsProgress = eq(0.1f), ) } @@ -498,11 +494,11 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { val delay = 50 context.orCreateTestableResources.addOverride( R.dimen.lockscreen_shade_notifications_scrim_transition_distance, - distance + distance, ) context.orCreateTestableResources.addOverride( R.dimen.lockscreen_shade_notifications_scrim_transition_delay, - delay + delay, ) configurationController.notifyConfigurationChanged() @@ -511,7 +507,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { verify(scrimController) .transitionToFullShadeProgress( progress = anyFloat(), - lockScreenNotificationsProgress = eq(0f) + lockScreenNotificationsProgress = eq(0f), ) } @@ -522,11 +518,11 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { val delay = 50 context.orCreateTestableResources.addOverride( R.dimen.lockscreen_shade_notifications_scrim_transition_distance, - distance + distance, ) context.orCreateTestableResources.addOverride( R.dimen.lockscreen_shade_notifications_scrim_transition_delay, - delay + delay, ) configurationController.notifyConfigurationChanged() @@ -535,7 +531,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { verify(scrimController) .transitionToFullShadeProgress( progress = anyFloat(), - lockScreenNotificationsProgress = eq(1f) + lockScreenNotificationsProgress = eq(1f), ) } @@ -627,7 +623,7 @@ class LockscreenShadeTransitionControllerTest : SysuiTestCase() { */ private fun ScrimController.transitionToFullShadeProgress( progress: Float, - lockScreenNotificationsProgress: Float + lockScreenNotificationsProgress: Float, ) { setTransitionToFullShadeProgress(progress, lockScreenNotificationsProgress) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index c9ada7e7f5ba..b142fc2deea9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -155,6 +155,7 @@ import com.android.systemui.shade.ShadeController; import com.android.systemui.shade.ShadeControllerImpl; import com.android.systemui.shade.ShadeExpansionStateManager; import com.android.systemui.shade.ShadeLogger; +import com.android.systemui.shade.StatusBarLongPressGestureDetector; import com.android.systemui.shared.notifications.domain.interactor.NotificationSettingsInteractor; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyboardShortcutListSearch; @@ -174,7 +175,6 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.core.StatusBarConnectedDisplays; import com.android.systemui.statusbar.core.StatusBarInitializerImpl; -import com.android.systemui.statusbar.core.StatusBarOrchestrator; import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository; import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository; import com.android.systemui.statusbar.notification.NotifPipelineFlags; @@ -372,7 +372,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private EmergencyGestureIntentFactory mEmergencyGestureIntentFactory; @Mock private NotificationSettingsInteractor mNotificationSettingsInteractor; @Mock private ViewCaptureAwareWindowManager mViewCaptureAwareWindowManager; - @Mock private StatusBarOrchestrator mStatusBarOrchestrator; + @Mock private StatusBarLongPressGestureDetector mStatusBarLongPressGestureDetector; private ShadeController mShadeController; private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); private final FakeGlobalSettings mFakeGlobalSettings = new FakeGlobalSettings(); @@ -607,6 +607,7 @@ public class CentralSurfacesImplTest extends SysuiTestCase { mShadeController, mWindowRootViewVisibilityInteractor, mStatusBarKeyguardViewManager, + () -> mStatusBarLongPressGestureDetector, mViewMediatorCallback, mInitController, new Handler(TestableLooper.get(this).getLooper()), diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt index 638f195df00c..69efa87a9cac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt @@ -40,14 +40,13 @@ import com.android.systemui.flags.Flags import com.android.systemui.plugins.fakeDarkIconDispatcher import com.android.systemui.res.R import com.android.systemui.scene.ui.view.WindowRootView -import com.android.systemui.shade.LongPressGestureDetector import com.android.systemui.shade.ShadeControllerImpl import com.android.systemui.shade.ShadeLogger import com.android.systemui.shade.ShadeViewController +import com.android.systemui.shade.StatusBarLongPressGestureDetector import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor import com.android.systemui.statusbar.CommandQueue import com.android.systemui.statusbar.data.repository.fakeStatusBarContentInsetsProviderStore -import com.android.systemui.statusbar.data.repository.statusBarContentInsetsProviderStore import com.android.systemui.statusbar.policy.Clock import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.statusbar.window.StatusBarWindowStateController @@ -98,7 +97,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { @Mock private lateinit var windowRootView: Provider<WindowRootView> @Mock private lateinit var shadeLogger: ShadeLogger @Mock private lateinit var viewUtil: ViewUtil - @Mock private lateinit var longPressGestureDetector: LongPressGestureDetector + @Mock private lateinit var mStatusBarLongPressGestureDetector: StatusBarLongPressGestureDetector private lateinit var statusBarWindowStateController: StatusBarWindowStateController private lateinit var view: PhoneStatusBarView @@ -395,7 +394,7 @@ class PhoneStatusBarViewControllerTest : SysuiTestCase() { shadeControllerImpl, shadeViewController, panelExpansionInteractor, - { longPressGestureDetector }, + { mStatusBarLongPressGestureDetector }, windowRootView, shadeLogger, viewUtil, diff --git a/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt b/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt index 796ec9400249..45dcb28b23ee 100644 --- a/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/android/hardware/display/DisplayManagerKosmos.kt @@ -16,7 +16,12 @@ package android.hardware.display +import android.view.Display import com.android.systemui.kosmos.Kosmos -import com.android.systemui.util.mockito.mock +import org.mockito.kotlin.mock val Kosmos.displayManager by Kosmos.Fixture { mock<DisplayManager>() } + +val Kosmos.defaultDisplay: Display by Kosmos.Fixture { mock<Display>() } + +val Kosmos.rearDisplay: Display by Kosmos.Fixture { mock<Display>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt index 9c55820b797c..b8a095eae23e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/DeviceStateManagerKosmos.kt @@ -18,6 +18,7 @@ package com.android.systemui import android.hardware.devicestate.DeviceState import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY +import android.hardware.devicestate.DeviceState.PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY import android.hardware.devicestate.DeviceState.PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED @@ -44,7 +45,7 @@ val Kosmos.foldedDeviceStateList by .setSystemProperties( setOf( PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, - PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP + PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP, ) ) .setPhysicalProperties( @@ -57,7 +58,7 @@ val Kosmos.foldedDeviceStateList by .setSystemProperties( setOf( PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, - PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP + PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP, ) ) .setPhysicalProperties( @@ -70,14 +71,14 @@ val Kosmos.foldedDeviceStateList by .setSystemProperties( setOf( PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, - PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP + PROPERTY_POWER_CONFIGURATION_TRIGGER_SLEEP, ) ) .setPhysicalProperties( setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_CLOSED) ) .build() - ) + ), ) } @@ -88,7 +89,7 @@ val Kosmos.halfFoldedDeviceState by .setSystemProperties( setOf( PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, - PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE + PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE, ) ) .setPhysicalProperties( @@ -105,7 +106,7 @@ val Kosmos.unfoldedDeviceState by .setSystemProperties( setOf( PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_INNER_PRIMARY, - PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE + PROPERTY_POWER_CONFIGURATION_TRIGGER_WAKE, ) ) .setPhysicalProperties(setOf(PROPERTY_FOLDABLE_HARDWARE_CONFIGURATION_FOLD_IN_OPEN)) @@ -120,7 +121,22 @@ val Kosmos.rearDisplayDeviceState by .setSystemProperties( setOf( PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, - PROPERTY_FEATURE_REAR_DISPLAY + PROPERTY_FEATURE_REAR_DISPLAY, + ) + ) + .build() + ) + } + +val Kosmos.rearDisplayOuterDefaultDeviceState by + Kosmos.Fixture { + DeviceState( + DeviceState.Configuration.Builder(5 /* identifier */, "REAR_DISPLAY") + .setSystemProperties( + setOf( + PROPERTY_FOLDABLE_DISPLAY_CONFIGURATION_OUTER_PRIMARY, + PROPERTY_FEATURE_REAR_DISPLAY, + PROPERTY_FEATURE_REAR_DISPLAY_OUTER_DEFAULT, ) ) .build() diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/RearDisplayInnerDialogDelegateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/RearDisplayInnerDialogDelegateKosmos.kt new file mode 100644 index 000000000000..6f5985536fe7 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/RearDisplayInnerDialogDelegateKosmos.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 + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.reardisplay.RearDisplayInnerDialogDelegate +import org.mockito.kotlin.mock + +val Kosmos.rearDisplayInnerDialogDelegateFactory by + Kosmos.Fixture { mock<RearDisplayInnerDialogDelegate.Factory>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt index 32469b6cfc30..ad38bbeba1a8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/flags/FakeFeatureFlags.kt @@ -23,13 +23,13 @@ import java.io.PrintWriter class FakeFeatureFlagsClassic : FakeFeatureFlags() +val FeatureFlagsClassic.fake + get() = this as FakeFeatureFlagsClassic + @Deprecated( message = "Use FakeFeatureFlagsClassic instead.", replaceWith = - ReplaceWith( - "FakeFeatureFlagsClassic", - "com.android.systemui.flags.FakeFeatureFlagsClassic", - ), + ReplaceWith("FakeFeatureFlagsClassic", "com.android.systemui.flags.FakeFeatureFlagsClassic"), ) open class FakeFeatureFlags : FeatureFlagsClassic { private val booleanFlags = mutableMapOf<String, Boolean>() @@ -105,6 +105,7 @@ open class FakeFeatureFlags : FeatureFlagsClassic { listener.onFlagChanged( object : FlagListenable.FlagEvent { override val flagName = flag.name + override fun requestNoRestart() {} } ) @@ -165,7 +166,7 @@ open class FakeFeatureFlags : FeatureFlagsClassic { @Module(includes = [FakeFeatureFlagsClassicModule.Bindings::class]) class FakeFeatureFlagsClassicModule( - @get:Provides val fakeFeatureFlagsClassic: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic(), + @get:Provides val fakeFeatureFlagsClassic: FakeFeatureFlagsClassic = FakeFeatureFlagsClassic() ) { constructor( @@ -175,7 +176,9 @@ class FakeFeatureFlagsClassicModule( @Module interface Bindings { @Binds fun bindFake(fake: FakeFeatureFlagsClassic): FeatureFlagsClassic + @Binds fun bindClassic(classic: FeatureFlagsClassic): FeatureFlags + @Binds fun bindFakeClassic(fake: FakeFeatureFlagsClassic): FakeFeatureFlags } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt index 3cd613b21f4b..3d60abf59d62 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt @@ -71,6 +71,8 @@ import com.android.systemui.shade.shadeController import com.android.systemui.shade.ui.viewmodel.notificationShadeWindowModel import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel import com.android.systemui.statusbar.data.repository.fakeStatusBarModePerDisplayRepository +import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository +import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor @@ -78,7 +80,7 @@ import com.android.systemui.statusbar.notification.stack.domain.interactor.heads import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor import com.android.systemui.statusbar.phone.keyguardBypassController import com.android.systemui.statusbar.phone.scrimController -import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository import com.android.systemui.statusbar.pipeline.wifi.data.repository.fakeWifiRepository import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.wifiInteractor import com.android.systemui.statusbar.policy.configurationController @@ -126,7 +128,7 @@ class KosmosJavaAdapter() { val keyguardStatusBarViewModel by lazy { kosmos.keyguardStatusBarViewModel } val powerRepository by lazy { kosmos.fakePowerRepository } val clock by lazy { kosmos.systemClock } - val mobileConnectionsRepository by lazy { kosmos.fakeMobileConnectionsRepository } + val mobileConnectionsRepository by lazy { kosmos.mobileConnectionsRepository } val simBouncerInteractor by lazy { kosmos.simBouncerInteractor } val statusBarStateController by lazy { kosmos.statusBarStateController } val statusBarModePerDisplayRepository by lazy { kosmos.fakeStatusBarModePerDisplayRepository } @@ -183,4 +185,6 @@ class KosmosJavaAdapter() { val lockscreenToGlanceableHubTransitionViewModel by lazy { kosmos.lockscreenToGlanceableHubTransitionViewModel } + val disableFlagsInteractor by lazy { kosmos.disableFlagsInteractor } + val fakeDisableFlagsRepository by lazy { kosmos.fakeDisableFlagsRepository } } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt index 4ed491233f3c..45d5b387fea0 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModelKosmos.kt @@ -33,7 +33,7 @@ import com.android.systemui.qs.panels.ui.viewmodel.mediaInRowInLandscapeViewMode import com.android.systemui.qs.ui.viewmodel.quickSettingsContainerViewModelFactory import com.android.systemui.shade.largeScreenHeaderHelper import com.android.systemui.shade.transition.largeScreenShadeInterpolator -import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository +import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor import com.android.systemui.statusbar.sysuiStatusBarStateController import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -51,7 +51,7 @@ val Kosmos.qsFragmentComposeViewModelFactory by footerActionsController, sysuiStatusBarStateController, deviceEntryInteractor, - disableFlagsRepository, + disableFlagsInteractor, keyguardTransitionInteractor, largeScreenShadeInterpolator, configurationInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt index 8b124258909a..a4a63ec6ca21 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/domain/resolver/SceneResolverKosmos.kt @@ -21,6 +21,7 @@ package com.android.systemui.scene.domain.resolver import com.android.compose.animation.scene.SceneKey import com.android.systemui.deviceentry.domain.interactor.deviceEntryInteractor import com.android.systemui.keyguard.domain.interactor.keyguardEnabledInteractor +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope import com.android.systemui.scene.shared.model.SceneFamilies @@ -34,6 +35,7 @@ val Kosmos.homeSceneFamilyResolver by HomeSceneFamilyResolver( applicationScope = applicationCoroutineScope, deviceEntryInteractor = deviceEntryInteractor, + keyguardInteractor = keyguardInteractor, keyguardEnabledInteractor = keyguardEnabledInteractor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt index 39f58aea82ef..af6d6249b4a8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt @@ -25,7 +25,7 @@ import com.android.systemui.power.domain.interactor.powerInteractor import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.shade.ShadeModule import com.android.systemui.shade.data.repository.shadeRepository -import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository +import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor import com.android.systemui.statusbar.phone.dozeParameters import com.android.systemui.statusbar.policy.data.repository.userSetupRepository import com.android.systemui.statusbar.policy.domain.interactor.deviceProvisioningInteractor @@ -60,7 +60,7 @@ val Kosmos.shadeInteractorImpl by ShadeInteractorImpl( scope = applicationCoroutineScope, deviceProvisioningInteractor = deviceProvisioningInteractor, - disableFlagsRepository = disableFlagsRepository, + disableFlagsInteractor = disableFlagsInteractor, dozeParams = dozeParameters, keyguardRepository = fakeKeyguardRepository, keyguardTransitionInteractor = keyguardTransitionInteractor, diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt index 466a3eb83e95..9dbb547a434d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/data/repository/FakeDisableFlagsRepository.kt @@ -15,7 +15,7 @@ package com.android.systemui.statusbar.disableflags.data.repository import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel +import com.android.systemui.statusbar.disableflags.shared.model.DisableFlagsModel import dagger.Binds import dagger.Module import javax.inject.Inject diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.kt new file mode 100644 index 000000000000..7b4b047c130a --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/disableflags/domain/interactor/DisableFlagsInteractorKosmos.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.statusbar.disableflags.domain.interactor + +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.Kosmos.Fixture +import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository + +val Kosmos.disableFlagsInteractor by Fixture { + DisableFlagsInteractor(repository = disableFlagsRepository) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt index d76defef3c97..99ed4f0db64d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/airplane/domain/interactor/AirplaneModeInteractorKosmos.kt @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.pipeline.airplane.domain.interactor import com.android.systemui.kosmos.Kosmos import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository -import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository +import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository val Kosmos.airplaneModeInteractor: AirplaneModeInteractor by @@ -26,6 +26,6 @@ val Kosmos.airplaneModeInteractor: AirplaneModeInteractor by AirplaneModeInteractor( FakeAirplaneModeRepository(), FakeConnectivityRepository(), - fakeMobileConnectionsRepository, + mobileConnectionsRepository, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt index de73d3397db3..bfd46b664242 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepository.kt @@ -77,11 +77,7 @@ class FakeMobileConnectionsRepository( override fun getRepoForSubId(subId: Int): MobileConnectionRepository { return subIdRepos[subId] - ?: FakeMobileConnectionRepository( - subId, - tableLogBuffer, - ) - .also { subIdRepos[subId] = it } + ?: FakeMobileConnectionRepository(subId, tableLogBuffer).also { subIdRepos[subId] = it } } override val defaultDataSubRatConfig = MutableStateFlow(MobileMappings.Config()) @@ -135,3 +131,6 @@ class FakeMobileConnectionsRepository( const val LTE_ADVANCED_PRO = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO } } + +val MobileConnectionsRepository.fake + get() = this as FakeMobileConnectionsRepository diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt index cd22f1dd6acc..b952d71b157e 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKosmos.kt @@ -19,12 +19,20 @@ package com.android.systemui.statusbar.pipeline.mobile.data.repository import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.log.table.logcatTableLogBuffer +import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy +import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy + +val Kosmos.mobileMappingsProxy: MobileMappingsProxy by Fixture { FakeMobileMappingsProxy() } + +var Kosmos.mobileConnectionsRepositoryLogbufferName by Fixture { "FakeMobileConnectionsRepository" } val Kosmos.fakeMobileConnectionsRepository by Fixture { FakeMobileConnectionsRepository( - tableLogBuffer = logcatTableLogBuffer(this, "FakeMobileConnectionsRepository"), + mobileMappings = mobileMappingsProxy, + tableLogBuffer = logcatTableLogBuffer(this, mobileConnectionsRepositoryLogbufferName), ) } -val Kosmos.mobileConnectionsRepository by - Fixture<MobileConnectionsRepository> { fakeMobileConnectionsRepository } +val Kosmos.mobileConnectionsRepository: MobileConnectionsRepository by Fixture { + fakeMobileConnectionsRepository +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt index 8e656cf002ce..00bfa994aabd 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt @@ -18,7 +18,5 @@ package com.android.systemui.statusbar.pipeline.shared.data.repository import com.android.systemui.kosmos.Kosmos -val Kosmos.fakeConnectivityRepository: FakeConnectivityRepository by - Kosmos.Fixture { FakeConnectivityRepository() } val Kosmos.connectivityRepository: ConnectivityRepository by - Kosmos.Fixture { fakeConnectivityRepository } + Kosmos.Fixture { FakeConnectivityRepository() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt index 331e2fad19cb..c69d9a29a9b4 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/FakeConnectivityRepository.kt @@ -42,10 +42,7 @@ class FakeConnectivityRepository : ConnectivityRepository { * validated */ @JvmOverloads - fun setMobileConnected( - default: Boolean = true, - validated: Boolean = true, - ) { + fun setMobileConnected(default: Boolean = true, validated: Boolean = true) { defaultConnections.value = DefaultConnectionModel( mobile = DefaultConnectionModel.Mobile(default), @@ -55,10 +52,7 @@ class FakeConnectivityRepository : ConnectivityRepository { /** Similar convenience method for ethernet */ @JvmOverloads - fun setEthernetConnected( - default: Boolean = true, - validated: Boolean = true, - ) { + fun setEthernetConnected(default: Boolean = true, validated: Boolean = true) { defaultConnections.value = DefaultConnectionModel( ethernet = DefaultConnectionModel.Ethernet(default), @@ -67,10 +61,7 @@ class FakeConnectivityRepository : ConnectivityRepository { } @JvmOverloads - fun setWifiConnected( - default: Boolean = true, - validated: Boolean = true, - ) { + fun setWifiConnected(default: Boolean = true, validated: Boolean = true) { defaultConnections.value = DefaultConnectionModel( wifi = DefaultConnectionModel.Wifi(default), @@ -78,3 +69,6 @@ class FakeConnectivityRepository : ConnectivityRepository { ) } } + +val ConnectivityRepository.fake + get() = this as FakeConnectivityRepository diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt index 385a813996ff..13fde9608017 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractorKosmos.kt @@ -17,7 +17,7 @@ package com.android.systemui.statusbar.pipeline.shared.domain.interactor import com.android.systemui.kosmos.Kosmos -import com.android.systemui.statusbar.disableflags.data.repository.fakeDisableFlagsRepository +import com.android.systemui.statusbar.disableflags.domain.interactor.disableFlagsInteractor val Kosmos.collapsedStatusBarInteractor: CollapsedStatusBarInteractor by - Kosmos.Fixture { CollapsedStatusBarInteractor(fakeDisableFlagsRepository) } + Kosmos.Fixture { CollapsedStatusBarInteractor(disableFlagsInteractor) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt index 528c9d9ec64d..a110a49ccba8 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/FakeStatusBarWindowController.kt @@ -27,6 +27,9 @@ class FakeStatusBarWindowController : StatusBarWindowController { var isAttached = false private set + var isStopped = false + private set + override val statusBarHeight: Int = 0 override fun refreshStatusBarHeight() {} @@ -35,6 +38,10 @@ class FakeStatusBarWindowController : StatusBarWindowController { isAttached = true } + override fun stop() { + isStopped = true + } + override fun addViewToWindow(view: View, layoutParams: ViewGroup.LayoutParams) {} override val backgroundView: View diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt index 173e909e3b3f..23f2b4221825 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerKosmos.kt @@ -18,7 +18,8 @@ package com.android.systemui.statusbar.window import android.content.testableContext import android.view.windowManagerService -import com.android.app.viewcapture.viewCaptureAwareWindowManager +import com.android.app.viewcapture.realCaptureAwareWindowManager +import com.android.systemui.concurrency.fakeExecutor import com.android.systemui.fragments.fragmentService import com.android.systemui.kosmos.Kosmos import com.android.systemui.statusbar.phone.statusBarContentInsetsProvider @@ -32,12 +33,13 @@ val Kosmos.statusBarWindowControllerImpl by StatusBarWindowControllerImpl( testableContext, statusBarWindowViewInflater, - viewCaptureAwareWindowManager, + realCaptureAwareWindowManager, statusBarConfigurationController, windowManagerService, statusBarContentInsetsProvider, fragmentService, Optional.empty(), + fakeExecutor, ) } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStoreKosmos.kt new file mode 100644 index 000000000000..4941ceb7991d --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStoreKosmos.kt @@ -0,0 +1,48 @@ +/* + * 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.window + +import android.view.WindowManager +import com.android.app.viewcapture.ViewCaptureAwareWindowManager +import com.android.app.viewcapture.realCaptureAwareWindowManager +import com.android.systemui.display.data.repository.displayRepository +import com.android.systemui.display.data.repository.displayWindowPropertiesRepository +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.statusbar.data.repository.statusBarConfigurationControllerStore +import com.android.systemui.statusbar.data.repository.statusBarContentInsetsProviderStore +import org.mockito.kotlin.mock + +val Kosmos.multiDisplayStatusBarWindowControllerStore by + Kosmos.Fixture { + MultiDisplayStatusBarWindowControllerStore( + backgroundApplicationScope = applicationCoroutineScope, + controllerFactory = { _, _, _, _ -> mock() }, + displayWindowPropertiesRepository = displayWindowPropertiesRepository, + viewCaptureAwareWindowManagerFactory = + object : ViewCaptureAwareWindowManager.Factory { + override fun create( + windowManager: WindowManager + ): ViewCaptureAwareWindowManager { + return realCaptureAwareWindowManager + } + }, + statusBarConfigurationControllerStore = statusBarConfigurationControllerStore, + statusBarContentInsetsProviderStore = statusBarContentInsetsProviderStore, + displayRepository = displayRepository, + ) + } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java index 65f4122f773e..21a910b67dff 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettings.java @@ -16,6 +16,8 @@ package com.android.systemui.util.settings; +import static com.android.systemui.util.settings.JavaAdapter.newCoroutineScope; + import static kotlinx.coroutines.test.TestCoroutineDispatchersKt.StandardTestDispatcher; import android.annotation.NonNull; @@ -25,6 +27,7 @@ import android.database.ContentObserver; import android.net.Uri; import kotlinx.coroutines.CoroutineDispatcher; +import kotlinx.coroutines.CoroutineScope; import java.util.ArrayList; import java.util.HashMap; @@ -34,7 +37,7 @@ import java.util.Map; public class FakeGlobalSettings implements GlobalSettings { private final Map<String, String> mValues = new HashMap<>(); private final Map<String, List<ContentObserver>> mContentObserversAllUsers = new HashMap<>(); - private final CoroutineDispatcher mDispatcher; + private final CoroutineScope mSettingsScope; public static final Uri CONTENT_URI = Uri.parse("content://settings/fake_global"); @@ -44,11 +47,15 @@ public class FakeGlobalSettings implements GlobalSettings { */ @Deprecated public FakeGlobalSettings() { - mDispatcher = StandardTestDispatcher(/* scheduler = */ null, /* name = */ null); + CoroutineDispatcher dispatcher = StandardTestDispatcher( + /* scheduler = */ null, + /* name = */ null + ); + mSettingsScope = newCoroutineScope(dispatcher); } public FakeGlobalSettings(CoroutineDispatcher dispatcher) { - mDispatcher = dispatcher; + mSettingsScope = newCoroutineScope(dispatcher); } @NonNull @@ -61,8 +68,8 @@ public class FakeGlobalSettings implements GlobalSettings { @NonNull @Override - public CoroutineDispatcher getBackgroundDispatcher() { - return mDispatcher; + public CoroutineScope getSettingsScope() { + return mSettingsScope; } @Override diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt index 35fa2af7639f..78b78ca86a8d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeGlobalSettingsKosmos.kt @@ -19,5 +19,14 @@ package com.android.systemui.util.settings import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.Kosmos.Fixture import com.android.systemui.kosmos.testDispatcher +import kotlin.coroutines.CoroutineContext +import kotlinx.coroutines.CoroutineScope val Kosmos.fakeGlobalSettings: FakeGlobalSettings by Fixture { FakeGlobalSettings(testDispatcher) } + +object JavaAdapter { + @JvmStatic + fun newCoroutineScope(context: CoroutineContext): CoroutineScope { + return CoroutineScope(context) + } +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt index e5d113be7ca2..a3572754ab19 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/settings/FakeSettings.kt @@ -24,6 +24,7 @@ import android.util.Pair import androidx.annotation.VisibleForTesting import com.android.systemui.util.settings.SettingsProxy.CurrentUserIdProvider import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestDispatcher @@ -33,7 +34,7 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { private val contentObservers = mutableMapOf<SettingsKey, MutableList<ContentObserver>>() private val contentObserversAllUsers = mutableMapOf<String, MutableList<ContentObserver>>() - override val backgroundDispatcher: CoroutineDispatcher + override val settingsScope: CoroutineScope @UserIdInt override var userId = UserHandle.USER_CURRENT override val currentUserProvider: CurrentUserIdProvider @@ -43,17 +44,17 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { by main test scope.""" ) constructor() { - backgroundDispatcher = StandardTestDispatcher(scheduler = null, name = null) + settingsScope = CoroutineScope(StandardTestDispatcher(scheduler = null, name = null)) currentUserProvider = CurrentUserIdProvider { userId } } constructor(dispatcher: CoroutineDispatcher) { - backgroundDispatcher = dispatcher + settingsScope = CoroutineScope(dispatcher) currentUserProvider = CurrentUserIdProvider { userId } } constructor(dispatcher: CoroutineDispatcher, currentUserProvider: CurrentUserIdProvider) { - backgroundDispatcher = dispatcher + settingsScope = CoroutineScope(dispatcher) this.currentUserProvider = currentUserProvider } @@ -77,7 +78,7 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { uri: Uri, notifyForDescendants: Boolean, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) { if (userHandle == UserHandle.USER_ALL) { contentObserversAllUsers @@ -107,31 +108,31 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { override suspend fun registerContentObserver( uri: Uri, notifyForDescendants: Boolean, - settingsObserver: ContentObserver + settingsObserver: ContentObserver, ) = suspendAdvanceDispatcher { super<UserSettingsProxy>.registerContentObserver( uri, notifyForDescendants, - settingsObserver + settingsObserver, ) } override fun registerContentObserverAsync( uri: Uri, notifyForDescendants: Boolean, - settingsObserver: ContentObserver + settingsObserver: ContentObserver, ): Job = advanceDispatcher { super<UserSettingsProxy>.registerContentObserverAsync( uri, notifyForDescendants, - settingsObserver + settingsObserver, ) } override suspend fun registerContentObserverForUser( name: String, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) = suspendAdvanceDispatcher { super<UserSettingsProxy>.registerContentObserverForUser(name, settingsObserver, userHandle) } @@ -139,12 +140,12 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { override fun registerContentObserverForUserAsync( name: String, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ): Job = advanceDispatcher { super<UserSettingsProxy>.registerContentObserverForUserAsync( name, settingsObserver, - userHandle + userHandle, ) } @@ -156,7 +157,7 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { override suspend fun registerContentObserverForUser( uri: Uri, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) = suspendAdvanceDispatcher { super<UserSettingsProxy>.registerContentObserverForUser(uri, settingsObserver, userHandle) } @@ -164,12 +165,12 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { override fun registerContentObserverForUserAsync( uri: Uri, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ): Job = advanceDispatcher { super<UserSettingsProxy>.registerContentObserverForUserAsync( uri, settingsObserver, - userHandle + userHandle, ) } @@ -177,13 +178,13 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { uri: Uri, settingsObserver: ContentObserver, userHandle: Int, - registered: Runnable + registered: Runnable, ): Job = advanceDispatcher { super<UserSettingsProxy>.registerContentObserverForUserAsync( uri, settingsObserver, userHandle, - registered + registered, ) } @@ -191,13 +192,13 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { name: String, notifyForDescendants: Boolean, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) = suspendAdvanceDispatcher { super<UserSettingsProxy>.registerContentObserverForUser( name, notifyForDescendants, settingsObserver, - userHandle + userHandle, ) } @@ -205,13 +206,13 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { name: String, notifyForDescendants: Boolean, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ) = advanceDispatcher { super<UserSettingsProxy>.registerContentObserverForUserAsync( name, notifyForDescendants, settingsObserver, - userHandle + userHandle, ) } @@ -219,13 +220,13 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { uri: Uri, notifyForDescendants: Boolean, settingsObserver: ContentObserver, - userHandle: Int + userHandle: Int, ): Job = advanceDispatcher { super<UserSettingsProxy>.registerContentObserverForUserAsync( uri, notifyForDescendants, settingsObserver, - userHandle + userHandle, ) } @@ -259,7 +260,7 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { tag: String?, makeDefault: Boolean, userHandle: Int, - overrideableByRestore: Boolean + overrideableByRestore: Boolean, ): Boolean { val key = SettingsKey(userHandle, getUriFor(name).toString()) values[key] = value @@ -275,7 +276,7 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { name: String, value: String?, tag: String?, - makeDefault: Boolean + makeDefault: Boolean, ): Boolean { return putString(name, value) } @@ -293,8 +294,9 @@ class FakeSettings : SecureSettings, SystemSettings, UserSettingsProxy { return result } + @OptIn(ExperimentalStdlibApi::class) private fun testDispatcherRunCurrent() { - val testDispatcher = backgroundDispatcher as? TestDispatcher + val testDispatcher = settingsScope.coroutineContext[CoroutineDispatcher] as? TestDispatcher testDispatcher?.scheduler?.runCurrent() } diff --git a/ravenwood/scripts/run-ravenwood-tests.sh b/ravenwood/scripts/run-ravenwood-tests.sh index fe2269a8dc38..27c5ea1bd0d7 100755 --- a/ravenwood/scripts/run-ravenwood-tests.sh +++ b/ravenwood/scripts/run-ravenwood-tests.sh @@ -33,7 +33,7 @@ include_re="" exclude_re="" smoke_exclude_re="" dry_run="" -while getopts "sx:f:dt" opt; do +while getopts "sx:f:dtb" opt; do case "$opt" in s) # Remove slow tests. @@ -52,8 +52,13 @@ case "$opt" in dry_run="echo" ;; t) + # Redirect log to terminal export RAVENWOOD_LOG_OUT=$(tty) ;; + b) + # Build only + ATEST=m + ;; '?') exit 1 ;; @@ -99,11 +104,16 @@ done # Calculate the removed tests. -diff="$(diff <(echo "${all_tests[@]}" | tr ' ' '\n') <(echo "${targets[@]}" | tr ' ' '\n') )" +diff="$(diff <(echo "${all_tests[@]}" | tr ' ' '\n') <(echo "${targets[@]}" | tr ' ' '\n') | grep -v [0-9] )" if [[ "$diff" != "" ]]; then echo "Excluded tests:" echo "$diff" fi -$dry_run ${ATEST:-atest} "${targets[@]}" +run() { + echo "Running: ${@}" + "${@}" +} + +run $dry_run ${ATEST:-atest} "${targets[@]}" diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 827e3effcf32..762665c00e05 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -16,6 +16,7 @@ package com.android.server.appwidget; +import static android.appwidget.flags.Flags.checkRemoteViewsUriPermission; import static android.appwidget.flags.Flags.remoteAdapterConversion; import static android.appwidget.flags.Flags.remoteViewsProto; import static android.appwidget.flags.Flags.removeAppWidgetServiceIoFromCriticalPath; @@ -62,6 +63,7 @@ import android.appwidget.AppWidgetProviderInfo; import android.appwidget.PendingHostUpdate; import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.Intent.FilterComparison; @@ -150,6 +152,8 @@ import com.android.modules.utils.TypedXmlSerializer; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.WidgetBackupProvider; +import com.android.server.uri.GrantUri; +import com.android.server.uri.UriGrantsManagerInternal; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -2548,6 +2552,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku // Make sure the package runs under the caller uid. mSecurityPolicy.enforceCallFromPackage(callingPackage); + // Make sure RemoteViews do not contain URIs that the caller cannot access. + if (checkRemoteViewsUriPermission()) { + checkRemoteViewsUris(views); + } synchronized (mLock) { ensureGroupStateLoadedLocked(userId); @@ -2568,6 +2576,39 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } /** + * Checks that all of the Uris in the given RemoteViews are accessible to the caller. + */ + private void checkRemoteViewsUris(RemoteViews views) { + UriGrantsManagerInternal uriGrantsManager = LocalServices.getService( + UriGrantsManagerInternal.class); + int callingUid = Binder.getCallingUid(); + int callingUser = UserHandle.getCallingUserId(); + views.visitUris(uri -> { + switch (uri.getScheme()) { + // Check that content:// URIs are accessible to the caller. + case ContentResolver.SCHEME_CONTENT: + boolean canAccessUri = uriGrantsManager.checkUriPermission( + GrantUri.resolve(callingUser, uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION), callingUid, + Intent.FLAG_GRANT_READ_URI_PERMISSION, + /* isFullAccessForContentUri= */ true); + if (!canAccessUri) { + throw new SecurityException( + "Provider uid " + callingUid + " cannot access URI " + uri); + } + break; + // android.resource:// URIs are always allowed. + case ContentResolver.SCHEME_ANDROID_RESOURCE: + break; + // file:// and any other schemes are disallowed. + case ContentResolver.SCHEME_FILE: + default: + throw new SecurityException("Disallowed URI " + uri + " in RemoteViews."); + } + }); + } + + /** * Increment the counter of widget ids and return the new id. * * Typically called by {@link #allocateAppWidgetId} when a instance of widget is created, diff --git a/services/autofill/features.aconfig b/services/autofill/features.aconfig index bd46debf12ca..b3fe5f234bc2 100644 --- a/services/autofill/features.aconfig +++ b/services/autofill/features.aconfig @@ -2,6 +2,13 @@ package: "android.service.autofill" container: "system" flag { + name: "autofill_w_metrics" + namespace: "autofill" + description: "Guards against new metrics definitions introduced in W" + bug: "342676602" +} + +flag { name: "autofill_credman_integration" namespace: "autofill" description: "Guards Autofill Framework against Autofill-Credman integration" diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java index cd2a535aa2c5..e59bb42fd666 100644 --- a/services/autofill/java/com/android/server/autofill/Helper.java +++ b/services/autofill/java/com/android/server/autofill/Helper.java @@ -28,8 +28,11 @@ import android.app.ActivityManager; import android.app.assist.AssistStructure; import android.app.assist.AssistStructure.ViewNode; import android.app.assist.AssistStructure.WindowNode; +import android.app.slice.Slice; +import android.app.slice.SliceItem; import android.content.ComponentName; import android.content.Context; +import android.graphics.drawable.Icon; import android.hardware.display.DisplayManager; import android.metrics.LogMaker; import android.os.UserHandle; @@ -97,11 +100,12 @@ public final class Helper { @UserIdInt int userId, @NonNull RemoteViews rView) { final AtomicBoolean permissionsOk = new AtomicBoolean(true); - rView.visitUris(uri -> { - int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri); - boolean allowed = uriOwnerId == userId; - permissionsOk.set(allowed & permissionsOk.get()); - }); + rView.visitUris( + uri -> { + int uriOwnerId = android.content.ContentProvider.getUserIdFromUri(uri, userId); + boolean allowed = uriOwnerId == userId; + permissionsOk.set(allowed & permissionsOk.get()); + }); return permissionsOk.get(); } @@ -150,6 +154,47 @@ public final class Helper { return (ok ? rView : null); } + /** + * Checks the URI permissions of the icon in the slice, to see if the current userId is able to + * access it. + * + * <p>Returns null if slice contains user inaccessible icons + * + * <p>TODO: instead of returning a null Slice when the current userId cannot access an icon, + * return a reconstructed Slice without the icons. This is currently non-trivial since there are + * no public methods to generically add SliceItems to Slices + */ + public static @Nullable Slice sanitizeSlice(Slice slice) { + if (slice == null) { + return null; + } + + int userId = ActivityManager.getCurrentUser(); + + // Recontruct the Slice, filtering out bad icons + for (SliceItem sliceItem : slice.getItems()) { + if (!sliceItem.getFormat().equals(SliceItem.FORMAT_IMAGE)) { + // Not an image slice + continue; + } + + Icon icon = sliceItem.getIcon(); + if (icon.getType() != Icon.TYPE_URI + && icon.getType() != Icon.TYPE_URI_ADAPTIVE_BITMAP) { + // No URIs to sanitize + continue; + } + + int iconUriId = android.content.ContentProvider.getUserIdFromUri(icon.getUri(), userId); + + if (iconUriId != userId) { + Slog.w(TAG, "sanitizeSlice() user: " + userId + " cannot access icons in Slice"); + return null; + } + } + + return slice; + } @Nullable static AutofillId[] toArray(@Nullable ArraySet<AutofillId> set) { diff --git a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java index 38a412fa063d..50a26b355537 100644 --- a/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java +++ b/services/autofill/java/com/android/server/autofill/ui/RemoteInlineSuggestionViewConnector.java @@ -27,6 +27,7 @@ import android.service.autofill.InlinePresentation; import android.util.Slog; import com.android.server.LocalServices; +import com.android.server.autofill.Helper; import com.android.server.autofill.RemoteInlineSuggestionRenderService; import com.android.server.inputmethod.InputMethodManagerInternal; @@ -83,6 +84,10 @@ final class RemoteInlineSuggestionViewConnector { */ public boolean renderSuggestion(int width, int height, @NonNull IInlineSuggestionUiCallback callback) { + if (Helper.sanitizeSlice(mInlinePresentation.getSlice()) == null) { + if (sDebug) Slog.d(TAG, "Skipped rendering inline suggestion."); + return false; + } if (mRemoteRenderService != null) { if (sDebug) Slog.d(TAG, "Request to recreate the UI"); mRemoteRenderService.renderSuggestion(callback, mInlinePresentation, width, height, diff --git a/services/backup/flags.aconfig b/services/backup/flags.aconfig index d53f949753d8..fcb7934f7ca0 100644 --- a/services/backup/flags.aconfig +++ b/services/backup/flags.aconfig @@ -60,3 +60,12 @@ flag { bug: "331749778" is_fixed_read_only: true } + +flag { + name: "enable_restricted_mode_changes" + namespace: "onboarding" + description: "Enables the new framework behavior of not putting apps in restricted mode for " + "B&R operations in certain cases." + bug: "376661510" + is_fixed_read_only: true +} diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 466d477992b3..5de2fb30ac78 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -43,6 +43,7 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.AppGlobals; +import android.app.ApplicationThreadConstants; import android.app.IActivityManager; import android.app.IBackupAgent; import android.app.PendingIntent; @@ -59,6 +60,9 @@ import android.app.backup.IBackupObserver; import android.app.backup.IFullBackupRestoreObserver; import android.app.backup.IRestoreSession; import android.app.backup.ISelectBackupTransportCallback; +import android.app.compat.CompatChanges; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledSince; import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -298,6 +302,15 @@ public class UserBackupManagerService { private static final String BACKUP_FINISHED_ACTION = "android.intent.action.BACKUP_FINISHED"; private static final String BACKUP_FINISHED_PACKAGE_EXTRA = "packageName"; + /** + * Enables the OS making a decision on whether backup restricted mode should be used for apps + * that haven't explicitly opted in or out. See + * {@link PackageManager#PROPERTY_USE_RESTRICTED_BACKUP_MODE} for details. + */ + @ChangeId + @EnabledSince(targetSdkVersion = Build.VERSION_CODES.BAKLAVA) + public static final long OS_DECIDES_BACKUP_RESTRICTED_MODE = 376661510; + // Time delay for initialization operations that can be delayed so as not to consume too much // CPU on bring-up and increase time-to-UI. private static final long INITIALIZATION_DELAY_MILLIS = 3000; @@ -352,6 +365,9 @@ public class UserBackupManagerService { // Backups that we haven't started yet. Keys are package names. private final HashMap<String, BackupRequest> mPendingBackups = new HashMap<>(); + private final ArraySet<String> mRestoreNoRestrictedModePackages = new ArraySet<>(); + private final ArraySet<String> mBackupNoRestrictedModePackages = new ArraySet<>(); + // locking around the pending-backup management private final Object mQueueLock = new Object(); @@ -523,7 +539,8 @@ public class UserBackupManagerService { @VisibleForTesting UserBackupManagerService(Context context, PackageManager packageManager, LifecycleOperationStorage operationStorage, TransportManager transportManager, - BackupHandler backupHandler, BackupManagerConstants backupManagerConstants) { + BackupHandler backupHandler, BackupManagerConstants backupManagerConstants, + IActivityManager activityManager, ActivityManagerInternal activityManagerInternal) { mContext = context; mUserId = 0; @@ -534,6 +551,8 @@ public class UserBackupManagerService { mFullBackupQueue = new ArrayList<>(); mBackupHandler = backupHandler; mConstants = backupManagerConstants; + mActivityManager = activityManager; + mActivityManagerInternal = activityManagerInternal; mBaseStateDir = null; mDataDir = null; @@ -543,13 +562,11 @@ public class UserBackupManagerService { mRunInitReceiver = null; mRunInitIntent = null; mAgentTimeoutParameters = null; - mActivityManagerInternal = null; mAlarmManager = null; mWakelock = null; mBackupPreferences = null; mBackupPasswordManager = null; mPackageManagerBinder = null; - mActivityManager = null; mBackupManagerBinder = null; mScheduledBackupEligibility = null; } @@ -1651,9 +1668,11 @@ public class UserBackupManagerService { synchronized (mAgentConnectLock) { mConnecting = true; mConnectedAgent = null; + boolean useRestrictedMode = shouldUseRestrictedBackupModeForPackage(mode, + app.packageName); try { if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId, - backupDestination)) { + backupDestination, useRestrictedMode)) { Slog.d(TAG, addUserIdToLogMessage(mUserId, "awaiting agent for " + app)); // success; wait for the agent to arrive @@ -3103,6 +3122,91 @@ public class UserBackupManagerService { } } + /** + * Marks the given set of packages as packages that should not be put into restricted mode if + * they are started for the given {@link BackupAnnotations.OperationType}. + */ + public void setNoRestrictedModePackages(Set<String> packageNames, + @BackupAnnotations.OperationType int opType) { + if (opType == BackupAnnotations.OperationType.BACKUP) { + mBackupNoRestrictedModePackages.clear(); + mBackupNoRestrictedModePackages.addAll(packageNames); + } else if (opType == BackupAnnotations.OperationType.RESTORE) { + mRestoreNoRestrictedModePackages.clear(); + mRestoreNoRestrictedModePackages.addAll(packageNames); + } else { + throw new IllegalArgumentException("opType must be BACKUP or RESTORE"); + } + } + + /** + * Clears the list of packages that should not be put into restricted mode for either backup or + * restore. + */ + public void clearNoRestrictedModePackages() { + mBackupNoRestrictedModePackages.clear(); + mRestoreNoRestrictedModePackages.clear(); + } + + /** + * If the app has specified {@link PackageManager#PROPERTY_USE_RESTRICTED_BACKUP_MODE}, then + * its value is returned. If it hasn't and it targets an SDK below + * {@link Build.VERSION_CODES#BAKLAVA} then returns true. If it targets a newer SDK, then + * returns the decision made by the {@link android.app.backup.BackupTransport}. + * + * <p>When this method is called, we should have already asked the transport and cached its + * response in {@link #mBackupNoRestrictedModePackages} or + * {@link #mRestoreNoRestrictedModePackages} so this method will immediately return without + * any IPC to the transport. + */ + private boolean shouldUseRestrictedBackupModeForPackage( + @BackupAnnotations.OperationType int mode, String packageName) { + if (!Flags.enableRestrictedModeChanges()) { + return true; + } + + // Key/Value apps are never put in restricted mode. + if (mode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL + || mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) { + return false; + } + + try { + PackageManager.Property property = mPackageManager.getPropertyAsUser( + PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, + packageName, /* className= */ null, + mUserId); + if (property.isBoolean()) { + // If the package has explicitly specified, we won't ask the transport. + return property.getBoolean(); + } else { + Slog.w(TAG, PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE + + "must be a boolean."); + } + } catch (NameNotFoundException e) { + // This is expected when the package has not defined the property in its manifest. + } + + // The package has not specified the property. The behavior depends on the package's + // targetSdk. + // <36 gets the old behavior of always using restricted mode. + if (!CompatChanges.isChangeEnabled(OS_DECIDES_BACKUP_RESTRICTED_MODE, packageName, + UserHandle.of(mUserId))) { + return true; + } + + // Apps targeting >=36 get the behavior decided by the transport. + // By this point, we should have asked the transport and cached its decision. + if ((mode == ApplicationThreadConstants.BACKUP_MODE_FULL + && mBackupNoRestrictedModePackages.contains(packageName)) + || (mode == ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL + && mRestoreNoRestrictedModePackages.contains(packageName))) { + Slog.d(TAG, "Transport requested no restricted mode for: " + packageName); + return false; + } + return true; + } + private boolean startConfirmationUi(int token, String action) { try { Intent confIntent = new Intent(action); diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java index cca166b0939c..be9cdc8692cb 100644 --- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java +++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java @@ -16,6 +16,8 @@ package com.android.server.backup.fullbackup; +import static android.app.backup.BackupAnnotations.OperationType.BACKUP; + import static com.android.server.backup.BackupManagerService.DEBUG; import static com.android.server.backup.BackupManagerService.DEBUG_SCHEDULING; import static com.android.server.backup.BackupManagerService.MORE_DEBUG; @@ -34,6 +36,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.util.ArraySet; import android.util.EventLog; import android.util.Log; import android.util.Slog; @@ -388,6 +391,10 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba } } + // We ask the transport which packages should not be put in restricted mode and cache + // the result in UBMS to be used later when the apps are started for backup. + setNoRestrictedModePackages(transport, mPackages); + // Set up to send data to the transport final int N = mPackages.size(); int chunkSizeInBytes = 8 * 1024; // 8KB @@ -694,6 +701,9 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba mUserBackupManagerService.scheduleNextFullBackupJob(backoff); } + // Clear this to avoid using the memory until reboot. + mUserBackupManagerService.clearNoRestrictedModePackages(); + Slog.i(TAG, "Full data backup pass finished."); mUserBackupManagerService.getWakelock().release(); } @@ -722,6 +732,21 @@ public class PerformFullTransportBackupTask extends FullBackupTask implements Ba } } + private void setNoRestrictedModePackages(BackupTransportClient transport, + List<PackageInfo> packages) { + try { + Set<String> packageNames = new ArraySet<>(); + for (int i = 0; i < packages.size(); i++) { + packageNames.add(packages.get(i).packageName); + } + packageNames = transport.getPackagesThatShouldNotUseRestrictedMode(packageNames, + BACKUP); + mUserBackupManagerService.setNoRestrictedModePackages(packageNames, BACKUP); + } catch (RemoteException e) { + Slog.i(TAG, "Failed to retrieve no restricted mode packages from transport"); + } + } + // Run the backup and pipe it back to the given socket -- expects to run on // a standalone thread. The runner owns this half of the pipe, and closes // it to indicate EOD to the other end. diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index e536876f6cc3..5ee51a5aa189 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -53,6 +53,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; +import android.util.ArraySet; import android.util.EventLog; import android.util.Slog; @@ -482,6 +483,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { return; } + // We ask the transport which packages should not be put in restricted mode and cache + // the result in UBMS to be used later when the apps are started for restore. + setNoRestrictedModePackages(transport, packages); + RestoreDescription desc = transport.nextRestorePackage(); if (desc == null) { Slog.e(TAG, "No restore metadata available; halting"); @@ -1358,6 +1363,9 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { // Clear any ongoing session timeout. backupManagerService.getBackupHandler().removeMessages(MSG_RESTORE_SESSION_TIMEOUT); + // Clear this to avoid using the memory until reboot. + backupManagerService.clearNoRestrictedModePackages(); + // If we have a PM token, we must under all circumstances be sure to // handshake when we've finished. if (mPmToken > 0) { @@ -1819,4 +1827,20 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { return packageInfo; } + + @VisibleForTesting + void setNoRestrictedModePackages(BackupTransportClient transport, + PackageInfo[] packages) { + try { + Set<String> packageNames = new ArraySet<>(); + for (int i = 0; i < packages.length; i++) { + packageNames.add(packages[i].packageName); + } + packageNames = transport.getPackagesThatShouldNotUseRestrictedMode(packageNames, + RESTORE); + backupManagerService.setNoRestrictedModePackages(packageNames, RESTORE); + } catch (RemoteException e) { + Slog.i(TAG, "Failed to retrieve restricted mode packages from transport"); + } + } } diff --git a/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java b/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java index daf3415229ea..373811fef802 100644 --- a/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java +++ b/services/backup/java/com/android/server/backup/transport/BackupTransportClient.java @@ -17,6 +17,7 @@ package com.android.server.backup.transport; import android.annotation.Nullable; +import android.app.backup.BackupAnnotations; import android.app.backup.BackupTransport; import android.app.backup.IBackupManagerMonitor; import android.app.backup.RestoreDescription; @@ -26,6 +27,7 @@ import android.content.pm.PackageInfo; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.util.ArraySet; import android.util.Slog; import com.android.internal.backup.IBackupTransport; @@ -375,6 +377,26 @@ public class BackupTransportClient { } /** + * See + * {@link IBackupTransport#getPackagesThatShouldNotUseRestrictedMode(List, int, AndroidFuture)}. + */ + public Set<String> getPackagesThatShouldNotUseRestrictedMode(Set<String> packageNames, + @BackupAnnotations.OperationType + int operationType) throws RemoteException { + AndroidFuture<List<String>> resultFuture = mTransportFutures.newFuture(); + mTransportBinder.getPackagesThatShouldNotUseRestrictedMode(List.copyOf(packageNames), + operationType, + resultFuture); + List<String> resultList = getFutureResult(resultFuture); + Set<String> set = new ArraySet<>(); + if (resultList == null) { + return set; + } + set.addAll(resultList); + return set; + } + + /** * Allows the {@link TransportConnection} to notify this client * if the underlying transport has become unusable. If that happens * we want to cancel all active futures or callbacks. diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index fa228627c255..e57b00944f7c 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -65,6 +65,7 @@ import android.telephony.CellSignalStrengthLte; import android.telephony.CellSignalStrengthNr; import android.telephony.CellSignalStrengthTdscdma; import android.telephony.CellSignalStrengthWcdma; +import android.telephony.CellularIdentifierDisclosure; import android.telephony.DisconnectCause; import android.telephony.LinkCapacityEstimate; import android.telephony.LocationAccessPolicy; @@ -76,6 +77,7 @@ import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; import android.telephony.PreciseDisconnectCause; import android.telephony.Rlog; +import android.telephony.SecurityAlgorithmUpdate; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; @@ -590,7 +592,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { || events.contains(TelephonyCallback.EVENT_ALLOWED_NETWORK_TYPE_LIST_CHANGED) || events.contains(TelephonyCallback.EVENT_EMERGENCY_CALLBACK_MODE_CHANGED) || events.contains(TelephonyCallback - .EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED); + .EVENT_SIMULTANEOUS_CELLULAR_CALLING_SUBSCRIPTIONS_CHANGED) + || events.contains(TelephonyCallback.EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED) + || events.contains(TelephonyCallback.EVENT_SECURITY_ALGORITHMS_CHANGED); } private static final int MSG_USER_SWITCHED = 1; @@ -897,7 +901,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mIsSatelliteEnabled = new AtomicBoolean(); mWasSatelliteEnabledNotified = new AtomicBoolean(); - for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; @@ -3825,7 +3828,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - /** * Notify external listeners that carrier roaming non-terrestrial network * signal strength changed. @@ -3835,7 +3837,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { public void notifyCarrierRoamingNtnSignalStrengthChanged(int subId, @NonNull NtnSignalStrength ntnSignalStrength) { if (!checkNotifyPermission("notifyCarrierRoamingNtnSignalStrengthChanged")) { - log("nnotifyCarrierRoamingNtnSignalStrengthChanged: caller does not have required " + log("notifyCarrierRoamingNtnSignalStrengthChanged: caller does not have required " + "permissions."); return; } @@ -3863,6 +3865,98 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + /** + * Notify that the radio security algorithms have changed. + * + * @param phoneId the phone id. + * @param subId the subId. + * @param update the security algorithm update. + */ + public void notifySecurityAlgorithmsChanged(int phoneId, int subId, + SecurityAlgorithmUpdate update) { + if (!Flags.securityAlgorithmsUpdateIndications()) { + log("Not available due to securityAlgorithmsUpdateIndications() flag"); + return; + } + if (!checkNotifyPermission("notifySecurityAlgorithmChanged()")) { + return; + } + + synchronized (mRecords) { + if (validatePhoneId(phoneId)) { + if (update == null) { + loge("SecurityAlgorithmUpdate is null, subId=" + subId + + ", phoneId=" + phoneId); + // Listeners shouldn't be updated for null updates. + return; + } + + for (Record r : mRecords) { + if (r.matchTelephonyCallbackEvent( + TelephonyCallback.EVENT_SECURITY_ALGORITHMS_CHANGED) + && idMatch(r, subId, phoneId)) { + try { + if (VDBG) { + log("notifySecurityAlgorithmsChanged: securityAlgorithmUpdate= " + + update); + } + r.callback.onSecurityAlgorithmsChanged(update); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + + /** + * Notify of a cellular identifier disclosure. + * + * @param phoneId the phone id. + * @param subId the subId. + * @param disclosure the cellular identifier disclosure. + */ + public void notifyCellularIdentifierDisclosedChanged(int phoneId, int subId, + @NonNull CellularIdentifierDisclosure disclosure) { + if (!Flags.cellularIdentifierDisclosureIndications()) { + log("Not available due to cellularIdentifierDisclosureIndications() flag"); + return; + } + if (!checkNotifyPermission("notifyCellularIdentifierDisclosedChanged()")) { + return; + } + + synchronized (mRecords) { + if (validatePhoneId(phoneId)) { + if (disclosure == null) { + loge("CellularIdentifierDisclosure is null, subId=" + subId + + ", phoneId=" + phoneId); + // Listeners shouldn't be updated for null disclosures. + return; + } + + for (Record r : mRecords) { + if (r.matchTelephonyCallbackEvent( + TelephonyCallback.EVENT_CELLULAR_IDENTIFIER_DISCLOSED_CHANGED) + && idMatch(r, subId, phoneId)) { + try { + if (VDBG) { + log("notifyCellularIdentifierDisclosedChanged: disclosure= " + + disclosure); + } + r.callback.onCellularIdentifierDisclosedChanged(disclosure); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + @NeverCompile // Avoid size overhead of debugging code. @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index dfddc089e4a4..d880bce921aa 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -478,7 +478,6 @@ import com.android.server.wm.WindowProcessController; import dalvik.annotation.optimization.NeverCompile; import dalvik.system.VMRuntime; - import libcore.util.EmptyArray; import java.io.File; @@ -4493,16 +4492,11 @@ public class ActivityManagerService extends IActivityManager.Stub Slog.w(TAG, "Unattached app died before backup, skipping"); final int userId = app.userId; final String packageName = app.info.packageName; - mHandler.post(new Runnable() { - @Override - public void run() { - try { - IBackupManager bm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentDisconnectedForUser(userId, packageName); - } catch (RemoteException e) { - // Can't happen; the backup manager is local - } + mHandler.post(() -> { + try { + getBackupManager().agentDisconnectedForUser(userId, packageName); + } catch (RemoteException e) { + // Can't happen; the backup manager is local } }); } @@ -4673,7 +4667,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) { isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID && ((backupTarget.backupMode == BackupRecord.RESTORE_FULL) - || (backupTarget.backupMode == BackupRecord.BACKUP_FULL)); + || (backupTarget.backupMode == BackupRecord.BACKUP_FULL)) + && backupTarget.useRestrictedMode; } final ActiveInstrumentation instr = app.getActiveInstrumentation(); @@ -13499,16 +13494,11 @@ public class ActivityManagerService extends IActivityManager.Stub if (backupTarget != null && pid == backupTarget.app.getPid()) { if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App " + backupTarget.appInfo + " died during backup"); - mHandler.post(new Runnable() { - @Override - public void run() { - try { - IBackupManager bm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentDisconnectedForUser(app.userId, app.info.packageName); - } catch (RemoteException e) { - // can't happen; backup manager is local - } + mHandler.post(() -> { + try { + getBackupManager().agentDisconnectedForUser(app.userId, app.info.packageName); + } catch (RemoteException e) { + // can't happen; backup manager is local } }); } @@ -14011,7 +14001,7 @@ public class ActivityManagerService extends IActivityManager.Stub // instantiated. The backup agent will invoke backupAgentCreated() on the // activity manager to announce its creation. public boolean bindBackupAgent(String packageName, int backupMode, int targetUserId, - @BackupDestination int backupDestination) { + @BackupDestination int backupDestination, boolean useRestrictedMode) { long startTimeNs = SystemClock.uptimeNanos(); if (DEBUG_BACKUP) { Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode @@ -14096,7 +14086,8 @@ public class ActivityManagerService extends IActivityManager.Stub + app.packageName + ": " + e); } - BackupRecord r = new BackupRecord(app, backupMode, targetUserId, backupDestination); + BackupRecord r = new BackupRecord(app, backupMode, targetUserId, backupDestination, + useRestrictedMode); ComponentName hostingName = (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL || backupMode == ApplicationThreadConstants.BACKUP_MODE_RESTORE) @@ -14122,8 +14113,9 @@ public class ActivityManagerService extends IActivityManager.Stub // process, etc, then mark it as being in full backup so that certain calls to the // process can be blocked. This is not reset to false anywhere because we kill the // process after the full backup is done and the ProcessRecord will vaporize anyway. - if (UserHandle.isApp(app.uid) && - backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL) { + if (UserHandle.isApp(app.uid) + && backupMode == ApplicationThreadConstants.BACKUP_MODE_FULL + && r.useRestrictedMode) { proc.setInFullBackup(true); } r.app = proc; @@ -14221,9 +14213,7 @@ public class ActivityManagerService extends IActivityManager.Stub final long oldIdent = Binder.clearCallingIdentity(); try { - IBackupManager bm = IBackupManager.Stub.asInterface( - ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentConnectedForUser(userId, agentPackageName, agent); + getBackupManager().agentConnectedForUser(userId, agentPackageName, agent); } catch (RemoteException e) { // can't happen; the backup manager service is local } catch (Exception e) { @@ -18013,14 +18003,6 @@ public class ActivityManagerService extends IActivityManager.Stub @Override public void addStartInfoTimestamp(int key, long timestampNs, int uid, int pid, int userId) { - // For the simplification, we don't support USER_ALL nor USER_CURRENT here. - if (userId == UserHandle.USER_ALL || userId == UserHandle.USER_CURRENT) { - throw new IllegalArgumentException("Unsupported userId"); - } - - mUserController.handleIncomingUser(pid, uid, userId, true, - ALLOW_NON_FULL, "addStartInfoTimestampSystem", null); - addStartInfoTimestampInternal(key, timestampNs, userId, uid); } @@ -19353,4 +19335,8 @@ public class ActivityManagerService extends IActivityManager.Stub } return token; } + + private IBackupManager getBackupManager() { + return IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE)); + } } diff --git a/services/core/java/com/android/server/am/BackupRecord.java b/services/core/java/com/android/server/am/BackupRecord.java index 0b056d7883bf..64cc6f0e66e3 100644 --- a/services/core/java/com/android/server/am/BackupRecord.java +++ b/services/core/java/com/android/server/am/BackupRecord.java @@ -32,15 +32,18 @@ final class BackupRecord { final int userId; // user for which backup is performed final int backupMode; // full backup / incremental / restore @BackupDestination final int backupDestination; // see BackupAnnotations#BackupDestination + final boolean useRestrictedMode; // whether the app should be put into restricted backup mode ProcessRecord app; // where this agent is running or null // ----- Implementation ----- - BackupRecord(ApplicationInfo _appInfo, int _backupMode, int _userId, int _backupDestination) { + BackupRecord(ApplicationInfo _appInfo, int _backupMode, int _userId, int _backupDestination, + boolean _useRestrictedMode) { appInfo = _appInfo; backupMode = _backupMode; userId = _userId; backupDestination = _backupDestination; + useRestrictedMode = _useRestrictedMode; } public String toString() { diff --git a/services/core/java/com/android/server/am/BroadcastController.java b/services/core/java/com/android/server/am/BroadcastController.java index 446b3671a94a..c6cb67f4efa8 100644 --- a/services/core/java/com/android/server/am/BroadcastController.java +++ b/services/core/java/com/android/server/am/BroadcastController.java @@ -553,7 +553,7 @@ class BroadcastController { } BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId, receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps, - exported, mService.mPlatformCompat); + exported, callerApp.info, mService.mPlatformCompat); if (rl.containsFilter(filter)) { Slog.w(TAG, "Receiver with filter " + filter + " already registered for pid " + rl.pid diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java index 3c7fb52b11b4..a32d3cb86c24 100644 --- a/services/core/java/com/android/server/am/BroadcastFilter.java +++ b/services/core/java/com/android/server/am/BroadcastFilter.java @@ -16,10 +16,13 @@ package com.android.server.am; +import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.os.Binder; import android.os.UserHandle; import android.util.PrintWriterPrinter; import android.util.Printer; @@ -40,7 +43,7 @@ public final class BroadcastFilter extends IntentFilter { @ChangeId @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE) @VisibleForTesting - static final long CHANGE_RESTRICT_PRIORITY_VALUES = 371309185L; + static final long RESTRICT_PRIORITY_VALUES = 371309185L; // Back-pointer to the list this filter is in. final ReceiverList receiverList; @@ -54,11 +57,12 @@ public final class BroadcastFilter extends IntentFilter { final boolean visibleToInstantApp; public final boolean exported; final int initialPriority; + final ApplicationInfo applicationInfo; BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList, String _packageName, String _featureId, String _receiverId, String _requiredPermission, int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp, - boolean _exported, PlatformCompat platformCompat) { + boolean _exported, ApplicationInfo _applicationInfo, PlatformCompat platformCompat) { super(_filter); receiverList = _receiverList; packageName = _packageName; @@ -70,8 +74,10 @@ public final class BroadcastFilter extends IntentFilter { instantApp = _instantApp; visibleToInstantApp = _visibleToInstantApp; exported = _exported; + applicationInfo = _applicationInfo; initialPriority = getPriority(); - setPriority(calculateAdjustedPriority(owningUid, initialPriority, platformCompat)); + setPriority(calculateAdjustedPriority(owningUid, initialPriority, + applicationInfo, platformCompat)); } public @Nullable String getReceiverClassName() { @@ -84,6 +90,10 @@ public final class BroadcastFilter extends IntentFilter { return null; } + public @NonNull ApplicationInfo getApplicationInfo() { + return applicationInfo; + } + @NeverCompile public void dumpDebug(ProtoOutputStream proto, long fieldId) { long token = proto.start(fieldId); @@ -125,13 +135,18 @@ public final class BroadcastFilter extends IntentFilter { @VisibleForTesting static int calculateAdjustedPriority(int owningUid, int priority, - PlatformCompat platformCompat) { + ApplicationInfo applicationInfo, PlatformCompat platformCompat) { if (!Flags.restrictPriorityValues()) { return priority; } - if (!platformCompat.isChangeEnabledByUidInternalNoLogging( - CHANGE_RESTRICT_PRIORITY_VALUES, owningUid)) { - return priority; + final long token = Binder.clearCallingIdentity(); + try { + if (!platformCompat.isChangeEnabledInternalNoLogging( + RESTRICT_PRIORITY_VALUES, applicationInfo)) { + return priority; + } + } finally { + Binder.restoreCallingIdentity(token); } if (!UserHandle.isCore(owningUid)) { if (priority >= SYSTEM_HIGH_PRIORITY) { diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index 38df10a0bc8c..a1ab1eea3d3e 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -49,6 +49,7 @@ import android.content.IIntentReceiver; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; import android.os.Binder; import android.os.Bundle; @@ -57,7 +58,6 @@ import android.os.UserHandle; import android.util.ArrayMap; import android.util.IntArray; import android.util.PrintWriterPrinter; -import android.util.SparseBooleanArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; @@ -88,7 +88,7 @@ final class BroadcastRecord extends Binder { @ChangeId @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.BASE) @VisibleForTesting - static final long CHANGE_LIMIT_PRIORITY_SCOPE = 371307720L; + static final long LIMIT_PRIORITY_SCOPE = 371307720L; final @NonNull Intent intent; // the original intent that generated us final @Nullable ComponentName targetComp; // original component name set on the intent @@ -781,7 +781,7 @@ final class BroadcastRecord extends Binder { } else { if (Flags.limitPriorityScope()) { final boolean[] changeEnabled = calculateChangeStateForReceivers( - receivers, CHANGE_LIMIT_PRIORITY_SCOPE, platformCompat); + receivers, LIMIT_PRIORITY_SCOPE, platformCompat); // Priority of the previous tranche int lastTranchePriority = 0; @@ -865,25 +865,35 @@ final class BroadcastRecord extends Binder { @VisibleForTesting static @NonNull boolean[] calculateChangeStateForReceivers(@NonNull List<Object> receivers, long changeId, PlatformCompat platformCompat) { - final SparseBooleanArray changeStateForUids = new SparseBooleanArray(); + // TODO: b/371307720 - Remove this method as we are already avoiding the packagemanager + // calls by checking the changeId state using ApplicationInfos. + final ArrayMap<String, Boolean> changeStates = new ArrayMap<>(); final int count = receivers.size(); final boolean[] changeStateForReceivers = new boolean[count]; for (int i = 0; i < count; ++i) { - final int receiverUid = getReceiverUid(receivers.get(i)); + final ApplicationInfo receiverAppInfo = getReceiverAppInfo(receivers.get(i)); final boolean isChangeEnabled; - final int idx = changeStateForUids.indexOfKey(receiverUid); + final int idx = changeStates.indexOfKey(receiverAppInfo.packageName); if (idx >= 0) { - isChangeEnabled = changeStateForUids.valueAt(idx); + isChangeEnabled = changeStates.valueAt(idx); } else { - isChangeEnabled = platformCompat.isChangeEnabledByUidInternalNoLogging( - changeId, receiverUid); - changeStateForUids.put(receiverUid, isChangeEnabled); + isChangeEnabled = platformCompat.isChangeEnabledInternalNoLogging( + changeId, receiverAppInfo); + changeStates.put(receiverAppInfo.packageName, isChangeEnabled); } changeStateForReceivers[i] = isChangeEnabled; } return changeStateForReceivers; } + static ApplicationInfo getReceiverAppInfo(@NonNull Object receiver) { + if (receiver instanceof BroadcastFilter) { + return ((BroadcastFilter) receiver).getApplicationInfo(); + } else { + return ((ResolveInfo) receiver).activityInfo.applicationInfo; + } + } + static int getReceiverUid(@NonNull Object receiver) { if (receiver instanceof BroadcastFilter) { return ((BroadcastFilter) receiver).owningUid; diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index b51db137f293..98f738c38d63 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -351,7 +351,8 @@ class ProcessRecord implements WindowProcessListener { private String[] mIsolatedEntryPointArgs; /** - * Process is currently hosting a backup agent for backup or restore. + * Process is currently hosting a backup agent for backup or restore. Note that this is only set + * when the process is put into restricted backup mode. */ @GuardedBy("mService") private boolean mInFullBackup; diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java index 364497491785..14d3fbc22372 100644 --- a/services/core/java/com/android/server/am/ProcessServiceRecord.java +++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java @@ -393,6 +393,8 @@ final class ProcessServiceRecord { adj = ProcessList.PERCEPTIBLE_APP_ADJ; } else if (adj < ProcessList.PERCEPTIBLE_LOW_APP_ADJ) { adj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ; + } else if (Flags.addModifyRawOomAdjServiceLevel() && adj < ProcessList.SERVICE_ADJ) { + adj = ProcessList.SERVICE_ADJ; } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) { adj = ProcessList.CACHED_APP_MIN_ADJ; } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) { diff --git a/services/core/java/com/android/server/am/flags.aconfig b/services/core/java/com/android/server/am/flags.aconfig index 711b163ea424..c59c40fc9cd8 100644 --- a/services/core/java/com/android/server/am/flags.aconfig +++ b/services/core/java/com/android/server/am/flags.aconfig @@ -260,3 +260,13 @@ flag { description: "Use PROCESS_CAPABILITY_CPU_TIME to control unfreeze state." bug: "370817323" } + +flag { + name: "add_modify_raw_oom_adj_service_level" + namespace: "backstage_power" + description: "Add a SERVICE_ADJ level to the modifyRawOomAdj method" + bug: "374810368" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 6ba356990cac..6e6bf80e8c09 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -9224,6 +9224,9 @@ public class AudioService extends IAudioService.Stub return; } + // index values sent to APM are in the stream type SDK range, not *10 + int indexMinVolCurve = MIN_STREAM_VOLUME[mStreamType]; + int indexMaxVolCurve = MAX_STREAM_VOLUME[mStreamType]; synchronized (this) { if (mStreamType == AudioSystem.STREAM_VOICE_CALL) { if (MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] @@ -9234,11 +9237,15 @@ public class AudioService extends IAudioService.Stub if (!equalScoLeaVcIndexRange() && isStreamBluetoothSco(mStreamType)) { // SCO devices have a different min index mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10; + indexMinVolCurve = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO]; + indexMaxVolCurve = MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO]; mIndexStepFactor = 1.f; } else if (equalScoLeaVcIndexRange() && isStreamBluetoothComm(mStreamType)) { // For non SCO devices the stream state does not change the min index if (mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_SCO) { mIndexMin = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO] * 10; + indexMinVolCurve = MIN_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO]; + indexMaxVolCurve = MAX_STREAM_VOLUME[AudioSystem.STREAM_BLUETOOTH_SCO]; } else { mIndexMin = MIN_STREAM_VOLUME[mStreamType] * 10; } @@ -9259,7 +9266,7 @@ public class AudioService extends IAudioService.Stub } final int status = AudioSystem.initStreamVolume( - mStreamType, mIndexMin / 10, mIndexMax / 10); + mStreamType, indexMinVolCurve, indexMaxVolCurve); sVolumeLogger.enqueue(new EventLogger.StringEvent( "updateIndexFactors() stream:" + mStreamType + " index min/max:" + mIndexMin / 10 + "/" + mIndexMax / 10 + " indexStepFactor:" @@ -14159,10 +14166,10 @@ public class AudioService extends IAudioService.Stub * Update player event * @param piid Player id to update * @param event The new player event - * @param eventValue The value associated with this event + * @param eventValues The values associated with this event */ - public void playerEvent(int piid, int event, int eventValue) { - mPlaybackMonitor.playerEvent(piid, event, eventValue, Binder.getCallingUid()); + public void playerEvent(int piid, int event, int[] eventValues) { + mPlaybackMonitor.playerEvent(piid, event, eventValues, Binder.getCallingUid()); } /** diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java index b63b07f0453e..a62ac82f27eb 100644 --- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java +++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java @@ -20,6 +20,7 @@ import static android.media.AudioPlaybackConfiguration.EXTRA_PLAYER_EVENT_MUTE; import static android.media.AudioPlaybackConfiguration.MUTED_BY_APP_OPS; import static android.media.AudioPlaybackConfiguration.MUTED_BY_CLIENT_VOLUME; import static android.media.AudioPlaybackConfiguration.MUTED_BY_MASTER; +import static android.media.AudioPlaybackConfiguration.MUTED_BY_PORT_VOLUME; import static android.media.AudioPlaybackConfiguration.MUTED_BY_STREAM_MUTED; import static android.media.AudioPlaybackConfiguration.MUTED_BY_STREAM_VOLUME; import static android.media.AudioPlaybackConfiguration.MUTED_BY_VOLUME_SHAPER; @@ -364,10 +365,11 @@ public final class PlaybackActivityMonitor * @param eventValue The value associated with this event * @param binderUid Calling binder uid */ - public void playerEvent(int piid, int event, int eventValue, int binderUid) { + public void playerEvent(int piid, int event, int[] eventValues, int binderUid) { if (DEBUG) { - Log.v(TAG, TextUtils.formatSimple("playerEvent(piid=%d, event=%s, eventValue=%d)", - piid, AudioPlaybackConfiguration.playerStateToString(event), eventValue)); + Log.v(TAG, TextUtils.formatSimple("playerEvent(piid=%d, event=%s, eventValues=%d)", + piid, AudioPlaybackConfiguration.playerStateToString(event), + Arrays.toString(eventValues))); } boolean change; synchronized(mPlayerLock) { @@ -381,13 +383,13 @@ public final class PlaybackActivityMonitor // do not log nor dispatch events for "ignored" players other than the release return; } - sEventLogger.enqueue(new PlayerEvent(piid, event, eventValue)); + sEventLogger.enqueue(new PlayerEvent(piid, event, eventValues)); if (event == AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID) { if (portToPiidSimplification()) { - mPiidToPortId.put(piid, eventValue); + mPiidToPortId.put(piid, eventValues[0]); } else { - mPortIdToPiid.put(eventValue, piid); + mPortIdToPiid.put(eventValues[0], piid); } return; } else if (event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) { @@ -408,7 +410,7 @@ public final class PlaybackActivityMonitor if (checkConfigurationCaller(piid, apc, binderUid)) { //TODO add generation counter to only update to the latest state checkVolumeForPrivilegedAlarm(apc, event); - change = apc.handleStateEvent(event, eventValue); + change = apc.handleStateEvent(event, eventValues); } else { Log.e(TAG, "Error handling event " + event); change = false; @@ -444,7 +446,7 @@ public final class PlaybackActivityMonitor } if (DEBUG) { - Log.v(TAG, TextUtils.formatSimple("BLA portEvent(portId=%d, event=%s, extras=%s)", + Log.v(TAG, TextUtils.formatSimple("portEvent(portId=%d, event=%s, extras=%s)", portId, AudioPlaybackConfiguration.playerStateToString(event), extras)); } @@ -516,7 +518,7 @@ public final class PlaybackActivityMonitor mMutedPlayersAwaitingConnection.remove(Integer.valueOf(piid)); checkVolumeForPrivilegedAlarm(apc, AudioPlaybackConfiguration.PLAYER_STATE_RELEASED); change = apc.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_RELEASED, - AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID); + AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID); if (portToPiidSimplification()) { mPiidToPortId.delete(piid); @@ -1335,12 +1337,12 @@ public final class PlaybackActivityMonitor // only keeping the player interface ID as it uniquely identifies the player in the event final int mPlayerIId; final int mEvent; - final int mEventValue; + final int[] mEventValues; - PlayerEvent(int piid, int event, int eventValue) { + PlayerEvent(int piid, int event, int[] eventValues) { mPlayerIId = piid; mEvent = event; - mEventValue = eventValue; + mEventValues = eventValues; } @Override @@ -1352,35 +1354,40 @@ public final class PlaybackActivityMonitor switch (mEvent) { case AudioPlaybackConfiguration.PLAYER_UPDATE_PORT_ID: return AudioPlaybackConfiguration.toLogFriendlyPlayerState(mEvent) + " portId:" - + mEventValue + " mapped to player piid:" + mPlayerIId; + + Arrays.toString(mEventValues) + " mapped to player piid:" + + mPlayerIId; case AudioPlaybackConfiguration.PLAYER_UPDATE_DEVICE_ID: - if (mEventValue != 0) { - builder.append(" deviceId:").append(mEventValue); + if ((mEventValues.length > 0) && (mEventValues[0] != 0)) { + builder.append(" deviceIds:").append(Arrays.toString(mEventValues)); } return builder.toString(); case AudioPlaybackConfiguration.PLAYER_UPDATE_MUTED: builder.append(" source:"); - if (mEventValue <= 0) { + int eventValue = mEventValues[0]; + if (eventValue <= 0) { builder.append("none "); } else { - if ((mEventValue & MUTED_BY_MASTER) != 0) { + if ((eventValue & MUTED_BY_MASTER) != 0) { builder.append("masterMute "); } - if ((mEventValue & MUTED_BY_STREAM_VOLUME) != 0) { + if ((eventValue & MUTED_BY_STREAM_VOLUME) != 0) { builder.append("streamVolume "); } - if ((mEventValue & MUTED_BY_STREAM_MUTED) != 0) { + if ((eventValue & MUTED_BY_STREAM_MUTED) != 0) { builder.append("streamMute "); } - if ((mEventValue & MUTED_BY_APP_OPS) != 0) { + if ((eventValue & MUTED_BY_APP_OPS) != 0) { builder.append("appOps "); } - if ((mEventValue & MUTED_BY_CLIENT_VOLUME) != 0) { + if ((eventValue & MUTED_BY_CLIENT_VOLUME) != 0) { builder.append("clientVolume "); } - if ((mEventValue & MUTED_BY_VOLUME_SHAPER) != 0) { + if ((eventValue & MUTED_BY_VOLUME_SHAPER) != 0) { builder.append("volumeShaper "); } + if ((eventValue & MUTED_BY_PORT_VOLUME) != 0) { + builder.append("portVolume "); + } } return builder.toString(); default: @@ -1728,8 +1735,11 @@ public final class PlaybackActivityMonitor synchronized (mPlayerLock) { int piid = msg.arg1; + + int[] eventValues = new int[1]; + eventValues[0] = eventValue; sEventLogger.enqueue( - new PlayerEvent(piid, PLAYER_UPDATE_MUTED, eventValue)); + new PlayerEvent(piid, PLAYER_UPDATE_MUTED, eventValues)); final AudioPlaybackConfiguration apc = mPlayers.get(piid); if (apc == null || !apc.handleMutedEvent(eventValue)) { diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java index 65780238ede4..97a88542f0a4 100644 --- a/services/core/java/com/android/server/biometrics/BiometricService.java +++ b/services/core/java/com/android/server/biometrics/BiometricService.java @@ -101,6 +101,7 @@ import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Supplier; /** @@ -132,7 +133,7 @@ public class BiometricService extends SystemService { IGateKeeperService mGateKeeper; // Get and cache the available biometric authenticators and their associated info. - final ArrayList<BiometricSensor> mSensors = new ArrayList<>(); + final CopyOnWriteArrayList<BiometricSensor> mSensors = new CopyOnWriteArrayList<>(); @VisibleForTesting BiometricStrengthController mBiometricStrengthController; @@ -156,13 +157,13 @@ public class BiometricService extends SystemService { @NonNull private final Set<Integer> mSensorsPendingInvalidation; public static InvalidationTracker start(@NonNull Context context, - @NonNull ArrayList<BiometricSensor> sensors, - int userId, int fromSensorId, @NonNull IInvalidationCallback clientCallback) { + @NonNull List<BiometricSensor> sensors, int userId, + int fromSensorId, @NonNull IInvalidationCallback clientCallback) { return new InvalidationTracker(context, sensors, userId, fromSensorId, clientCallback); } private InvalidationTracker(@NonNull Context context, - @NonNull ArrayList<BiometricSensor> sensors, int userId, + @NonNull List<BiometricSensor> sensors, int userId, int fromSensorId, @NonNull IInvalidationCallback clientCallback) { mClientCallback = clientCallback; mSensorsPendingInvalidation = new ArraySet<>(); @@ -879,7 +880,7 @@ public class BiometricService extends SystemService { @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) @Override - public synchronized void registerAuthenticator(int id, int modality, + public void registerAuthenticator(int id, int modality, @Authenticators.Types int strength, @NonNull IBiometricAuthenticator authenticator) { diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java index afdc0c0294a6..6ed1ac859501 100644 --- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java +++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java @@ -226,10 +226,6 @@ class PreAuthInfo { return BIOMETRIC_NO_HARDWARE; } - if (sensor.modality == TYPE_FACE && biometricCameraManager.isAnyCameraUnavailable()) { - return BIOMETRIC_HARDWARE_NOT_DETECTED; - } - final boolean wasStrongEnough = Utils.isAtLeastStrength(sensor.oemStrength, requestedStrength); final boolean isStrongEnough = @@ -241,6 +237,10 @@ class PreAuthInfo { return BIOMETRIC_INSUFFICIENT_STRENGTH; } + if (sensor.modality == TYPE_FACE && biometricCameraManager.isAnyCameraUnavailable()) { + return BIOMETRIC_HARDWARE_NOT_DETECTED; + } + try { if (!sensor.impl.isHardwareDetected(opPackageName)) { return BIOMETRIC_HARDWARE_NOT_DETECTED; diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index eeac26031719..6feae34f1a2d 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -522,7 +522,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { // b/282922910 - we don't want apps sharing system uid and targeting // older target sdk to impact all system uid apps if (Flags.systemUidTargetSystemSdk() && !mIsWear && - uid == Process.SYSTEM_UID) { + uid == Process.SYSTEM_UID && appInfo != null) { appInfo.targetSdkVersion = Build.VERSION.SDK_INT; } return appInfo; diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java index 716661dd6c3c..68dc80fa51c8 100644 --- a/services/core/java/com/android/server/display/color/TintController.java +++ b/services/core/java/com/android/server/display/color/TintController.java @@ -19,6 +19,7 @@ package com.android.server.display.color; import android.animation.ValueAnimator; import android.content.Context; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; @@ -29,23 +30,33 @@ abstract class TintController { */ private static final long TRANSITION_DURATION = 3000L; + private final Object mLock = new Object(); + + @GuardedBy("mLock") private ValueAnimator mAnimator; + @GuardedBy("mLock") private Boolean mIsActivated; public ValueAnimator getAnimator() { - return mAnimator; + synchronized (mLock) { + return mAnimator; + } } public void setAnimator(ValueAnimator animator) { - mAnimator = animator; + synchronized (mLock) { + mAnimator = animator; + } } /** * Cancel the animator if it's still running. */ public void cancelAnimator() { - if (mAnimator != null) { - mAnimator.cancel(); + synchronized (mLock) { + if (mAnimator != null) { + mAnimator.cancel(); + } } } @@ -53,22 +64,30 @@ abstract class TintController { * End the animator if it's still running, jumping to the end state. */ public void endAnimator() { - if (mAnimator != null) { - mAnimator.end(); - mAnimator = null; + synchronized (mLock) { + if (mAnimator != null) { + mAnimator.end(); + mAnimator = null; + } } } public void setActivated(Boolean isActivated) { - mIsActivated = isActivated; + synchronized (mLock) { + mIsActivated = isActivated; + } } public boolean isActivated() { - return mIsActivated != null && mIsActivated; + synchronized (mLock) { + return mIsActivated != null && mIsActivated; + } } public boolean isActivatedStateNotSet() { - return mIsActivated == null; + synchronized (mLock) { + return mIsActivated == null; + } } public long getTransitionDurationMilliseconds() { diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig index 586d59492f57..e7ea868ca04f 100644 --- a/services/core/java/com/android/server/display/feature/display_flags.aconfig +++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig @@ -4,6 +4,14 @@ container: "system" # Important: Flags must be accessed through DisplayManagerFlags. flag { + name: "is_always_on_available_api" + namespace: "display_manager" + description: "Allows querying of AOD availability" + bug: "324046664" + is_fixed_read_only: true +} + +flag { name: "enable_port_in_display_layout" namespace: "display_manager" description: "Allows refering to displays by port in display layout" diff --git a/services/core/java/com/android/server/display/mode/SystemRequestObserver.java b/services/core/java/com/android/server/display/mode/SystemRequestObserver.java index 15f19cca99db..4a4c8da1a335 100644 --- a/services/core/java/com/android/server/display/mode/SystemRequestObserver.java +++ b/services/core/java/com/android/server/display/mode/SystemRequestObserver.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.os.IBinder; import android.os.RemoteException; +import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; @@ -28,12 +29,15 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; /** * SystemRequestObserver responsible for handling system requests to filter allowable display * modes */ class SystemRequestObserver { + private static final String TAG = "SystemRequestObserver"; + private final VotesStorage mVotesStorage; private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @@ -43,6 +47,7 @@ class SystemRequestObserver { } @Override public void binderDied(@NonNull IBinder who) { + Slog.d(TAG, "binder died: " + who); removeSystemRequestedVotes(who); who.unlinkToDeath(mDeathRecipient, 0); } @@ -83,9 +88,11 @@ class SystemRequestObserver { updateStorageLocked(displayId); } if (needLinkToDeath) { + Slog.d(TAG, "binder linking to death: " + token); token.linkToDeath(mDeathRecipient, 0); } } catch (RemoteException re) { + Slog.d(TAG, "linking to death failed: " + token, re); removeSystemRequestedVotes(token); } } @@ -94,14 +101,19 @@ class SystemRequestObserver { boolean needToUnlink = false; synchronized (mLock) { SparseArray<List<Integer>> modesByDisplay = mDisplaysRestrictions.get(token); - if (modesByDisplay != null) { + if (modesByDisplay != null && modesByDisplay.size() > 0) { modesByDisplay.remove(displayId); needToUnlink = modesByDisplay.size() == 0; updateStorageLocked(displayId); } } if (needToUnlink) { - token.unlinkToDeath(mDeathRecipient, 0); + try { + Slog.d(TAG, "binder unlinking to death: " + token); + token.unlinkToDeath(mDeathRecipient, 0); + } catch (NoSuchElementException e) { + Slog.d(TAG, "unlinking to death failed: " + token, e); + } } } diff --git a/services/core/java/com/android/server/input/AppLaunchShortcutManager.java b/services/core/java/com/android/server/input/AppLaunchShortcutManager.java index aef207f9c027..f3820e5935d4 100644 --- a/services/core/java/com/android/server/input/AppLaunchShortcutManager.java +++ b/services/core/java/com/android/server/input/AppLaunchShortcutManager.java @@ -21,6 +21,7 @@ import android.annotation.SuppressLint; import android.app.role.RoleManager; import android.content.Context; import android.content.Intent; +import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.hardware.input.AppLaunchData; import android.hardware.input.InputGestureData; @@ -137,11 +138,19 @@ final class AppLaunchShortcutManager { String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY); String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT); String roleName = parser.getAttributeValue(null, ATTRIBUTE_ROLE); - - // TODO(b/358569822): Shift bookmarks to use keycode instead of shortcutChar - int keycode = KeyEvent.KEYCODE_UNKNOWN; String shortcut = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT); - if (!TextUtils.isEmpty(shortcut)) { + int keycode; + int modifierState; + TypedArray a = mContext.getResources().obtainAttributes(parser, + R.styleable.Bookmark); + try { + keycode = a.getInt(R.styleable.Bookmark_keycode, KeyEvent.KEYCODE_UNKNOWN); + modifierState = a.getInt(R.styleable.Bookmark_modifierState, 0); + } finally { + a.recycle(); + } + if (keycode == KeyEvent.KEYCODE_UNKNOWN && !TextUtils.isEmpty(shortcut)) { + // Fetch keycode using shortcut char KeyEvent[] events = virtualKcm.getEvents(new char[]{shortcut.toLowerCase( Locale.ROOT).charAt(0)}); // Single key press can generate the character @@ -153,12 +162,17 @@ final class AppLaunchShortcutManager { Log.w(TAG, "Keycode required for bookmark with category=" + categoryName + " packageName=" + packageName + " className=" + className + " role=" + roleName + " shiftName=" + shiftName - + " shortcut=" + shortcut); + + " shortcut=" + shortcut + " modifierState=" + modifierState); continue; } - final boolean isShiftShortcut = (shiftName != null && shiftName.toLowerCase( - Locale.ROOT).equals("true")); + if (modifierState == 0) { + // Fetch modifierState using shiftName + boolean isShiftShortcut = shiftName != null && shiftName.toLowerCase( + Locale.ROOT).equals("true"); + modifierState = + KeyEvent.META_META_ON | (isShiftShortcut ? KeyEvent.META_SHIFT_ON : 0); + } AppLaunchData launchData = null; if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) { launchData = AppLaunchData.createLaunchDataForComponent(packageName, className); @@ -168,11 +182,9 @@ final class AppLaunchShortcutManager { launchData = AppLaunchData.createLaunchDataForRole(roleName); } if (launchData != null) { - Log.d(TAG, "adding shortcut " + launchData + "shift=" - + isShiftShortcut + " keycode=" + keycode); + Log.d(TAG, "adding shortcut " + launchData + " modifierState=" + + modifierState + " keycode=" + keycode); // All bookmarks are based on Action key - int modifierState = - KeyEvent.META_META_ON | (isShiftShortcut ? KeyEvent.META_SHIFT_ON : 0); InputGestureData bookmark = new InputGestureData.Builder() .setTrigger(InputGestureData.createKeyTrigger(keycode, modifierState)) .setKeyGestureType(KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION) diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java index 6f3540221b63..73d563069632 100644 --- a/services/core/java/com/android/server/input/InputGestureManager.java +++ b/services/core/java/com/android/server/input/InputGestureManager.java @@ -228,6 +228,28 @@ final class InputGestureManager { KeyEvent.META_META_ON | KeyEvent.META_ALT_ON, KeyGestureEvent.KEY_GESTURE_TYPE_ACTIVATE_SELECT_TO_SPEAK)); } + if (enableTaskResizingKeyboardShortcuts()) { + systemShortcuts.add(createKeyGesture( + KeyEvent.KEYCODE_LEFT_BRACKET, + KeyEvent.META_META_ON, + KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW + )); + systemShortcuts.add(createKeyGesture( + KeyEvent.KEYCODE_RIGHT_BRACKET, + KeyEvent.META_META_ON, + KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW + )); + systemShortcuts.add(createKeyGesture( + KeyEvent.KEYCODE_EQUALS, + KeyEvent.META_META_ON, + KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW + )); + systemShortcuts.add(createKeyGesture( + KeyEvent.KEYCODE_MINUS, + KeyEvent.META_META_ON, + KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW + )); + } if (keyboardA11yShortcutControl()) { if (InputSettings.isAccessibilityBounceKeysFeatureEnabled()) { systemShortcuts.add(createKeyGesture( @@ -257,28 +279,6 @@ final class InputGestureManager { KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_SLOW_KEYS )); } - if (enableTaskResizingKeyboardShortcuts()) { - systemShortcuts.add(createKeyGesture( - KeyEvent.KEYCODE_LEFT_BRACKET, - KeyEvent.META_ALT_ON, - KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW - )); - systemShortcuts.add(createKeyGesture( - KeyEvent.KEYCODE_RIGHT_BRACKET, - KeyEvent.META_ALT_ON, - KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW - )); - systemShortcuts.add(createKeyGesture( - KeyEvent.KEYCODE_EQUALS, - KeyEvent.META_ALT_ON, - KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW - )); - systemShortcuts.add(createKeyGesture( - KeyEvent.KEYCODE_MINUS, - KeyEvent.META_ALT_ON, - KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE - )); - } } synchronized (mGestureLock) { for (InputGestureData systemShortcut : systemShortcuts) { diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 82449ce89c2c..edad2473061c 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -193,7 +193,6 @@ public class InputManagerService extends IInputManager.Stub private DisplayManagerInternal mDisplayManagerInternal; private WindowManagerInternal mWindowManagerInternal; - private PackageManagerInternal mPackageManagerInternal; private final File mDoubleTouchGestureEnableFile; @@ -573,7 +572,6 @@ public class InputManagerService extends IInputManager.Stub mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); - mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mSettingsObserver.registerAndUpdate(); @@ -2937,10 +2935,11 @@ public class InputManagerService extends IInputManager.Stub private void enforceManageKeyGesturePermission() { // TODO(b/361567988): Use @EnforcePermission to enforce permission once flag guarding the // permission is rolled out - if (mSystemReady) { - String systemUIPackage = mContext.getString(R.string.config_systemUi); - int systemUIAppId = UserHandle.getAppId(mPackageManagerInternal - .getPackageUid(systemUIPackage, PackageManager.MATCH_SYSTEM_ONLY, + String systemUIPackage = mContext.getString(R.string.config_systemUi); + PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); + if (pm != null) { + int systemUIAppId = UserHandle.getAppId( + pm.getPackageUid(systemUIPackage, PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM)); if (UserHandle.getCallingAppId() == systemUIAppId) { return; diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java b/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java new file mode 100644 index 000000000000..c05f7a0c0e00 --- /dev/null +++ b/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java @@ -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.server.location.contexthub; + +import android.hardware.contexthub.EndpointId; +import android.hardware.contexthub.HubEndpointInfo; +import android.hardware.contexthub.IEndpointCallback; +import android.hardware.contexthub.Message; +import android.hardware.contexthub.MessageDeliveryStatus; +import android.os.RemoteException; + +/** IEndpointCallback implementation. */ +public class ContextHubHalEndpointCallback + extends android.hardware.contexthub.IEndpointCallback.Stub { + private final IEndpointLifecycleCallback mEndpointLifecycleCallback; + + /** Interface for listening for endpoint start and stop events. */ + public interface IEndpointLifecycleCallback { + /** Called when a batch of endpoints started. */ + void onEndpointStarted(HubEndpointInfo[] endpointInfos); + + /** Called when a batch of endpoints stopped. */ + void onEndpointStopped(HubEndpointInfo.HubEndpointIdentifier[] endpointIds, byte reason); + } + + ContextHubHalEndpointCallback(IEndpointLifecycleCallback endpointLifecycleCallback) { + mEndpointLifecycleCallback = endpointLifecycleCallback; + } + + @Override + public void onEndpointStarted(android.hardware.contexthub.EndpointInfo[] halEndpointInfos) + throws RemoteException { + if (halEndpointInfos.length == 0) { + return; + } + HubEndpointInfo[] endpointInfos = new HubEndpointInfo[halEndpointInfos.length]; + for (int i = 0; i < halEndpointInfos.length; i++) { + endpointInfos[i++] = new HubEndpointInfo(halEndpointInfos[i]); + } + mEndpointLifecycleCallback.onEndpointStarted(endpointInfos); + } + + @Override + public void onEndpointStopped(EndpointId[] halEndpointIds, byte reason) throws RemoteException { + HubEndpointInfo.HubEndpointIdentifier[] endpointIds = + new HubEndpointInfo.HubEndpointIdentifier[halEndpointIds.length]; + for (int i = 0; i < halEndpointIds.length; i++) { + endpointIds[i] = new HubEndpointInfo.HubEndpointIdentifier(halEndpointIds[i]); + } + mEndpointLifecycleCallback.onEndpointStopped(endpointIds, reason); + } + + @Override + public void onMessageReceived(int i, Message message) throws RemoteException {} + + @Override + public void onMessageDeliveryStatusReceived(int i, MessageDeliveryStatus messageDeliveryStatus) + throws RemoteException {} + + @Override + public void onEndpointSessionOpenRequest( + int i, EndpointId endpointId, EndpointId endpointId1, String s) + throws RemoteException {} + + @Override + public void onCloseEndpointSession(int i, byte b) throws RemoteException {} + + @Override + public void onEndpointSessionOpenComplete(int i) throws RemoteException {} + + @Override + public int getInterfaceVersion() throws RemoteException { + return IEndpointCallback.VERSION; + } + + @Override + public String getInterfaceHash() throws RemoteException { + return IEndpointCallback.HASH; + } +} diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java index f611c57dab03..946e89604553 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java @@ -31,6 +31,9 @@ import android.database.ContentObserver; import android.hardware.SensorPrivacyManager; import android.hardware.SensorPrivacyManagerInternal; import android.hardware.contexthub.ErrorCode; +import android.hardware.contexthub.HubEndpointInfo; +import android.hardware.contexthub.IContextHubEndpoint; +import android.hardware.contexthub.IContextHubEndpointCallback; import android.hardware.contexthub.MessageDeliveryStatus; import android.hardware.location.ContextHubInfo; import android.hardware.location.ContextHubMessage; @@ -249,6 +252,7 @@ public class ContextHubService extends IContextHubService.Stub { public void handleServiceRestart() { Log.i(TAG, "Recovering from Context Hub HAL restart..."); initExistingCallbacks(); + mHubInfoRegistry.onHalRestart(); resetSettings(); if (Flags.reconnectHostEndpointsAfterHalRestart()) { mClientManager.forEachClientOfHub(mContextHubId, @@ -330,6 +334,7 @@ public class ContextHubService extends IContextHubService.Stub { } initDefaultClientMap(); + initEndpointCallback(); initLocationSettingNotifications(); initWifiSettingNotifications(); @@ -508,6 +513,18 @@ public class ContextHubService extends IContextHubService.Stub { mDefaultClientMap = Collections.unmodifiableMap(defaultClientMap); } + private void initEndpointCallback() { + if (mHubInfoRegistry == null) { + return; + } + try { + mContextHubWrapper.registerEndpointCallback( + new ContextHubHalEndpointCallback(mHubInfoRegistry)); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException while registering IEndpointCallback", e); + } + } + /** * Initializes existing callbacks with the mContextHubWrapper for every context hub */ @@ -739,6 +756,36 @@ public class ContextHubService extends IContextHubService.Stub { return mHubInfoRegistry.getHubs(); } + @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @Override + public List<HubEndpointInfo> findEndpoints(long endpointId) { + super.findEndpoints_enforcePermission(); + if (mHubInfoRegistry == null) { + return Collections.emptyList(); + } + return mHubInfoRegistry.findEndpoints(endpointId); + } + + @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @Override + public List<HubEndpointInfo> findEndpointsWithService(String serviceDescriptor) { + super.findEndpointsWithService_enforcePermission(); + if (mHubInfoRegistry == null) { + return Collections.emptyList(); + } + return mHubInfoRegistry.findEndpointsWithService(serviceDescriptor); + } + + @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) + @Override + public IContextHubEndpoint registerEndpoint( + HubEndpointInfo pendingHubEndpointInfo, IContextHubEndpointCallback callback) + throws RemoteException { + super.registerEndpoint_enforcePermission(); + // TODO(b/375487784): Implement this + return null; + } + /** * Creates an internal load transaction callback to be used for old API clients * diff --git a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java index 68de9dbda2e1..d2b2331d54f3 100644 --- a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java +++ b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java @@ -16,45 +16,161 @@ package com.android.server.location.contexthub; +import android.hardware.contexthub.HubEndpointInfo; +import android.hardware.contexthub.HubServiceInfo; import android.hardware.location.HubInfo; import android.os.RemoteException; +import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + +import java.util.ArrayList; import java.util.Collections; import java.util.List; -class HubInfoRegistry { +class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycleCallback { private static final String TAG = "HubInfoRegistry"; + private final Object mLock = new Object(); private final IContextHubWrapper mContextHubWrapper; - private final List<HubInfo> mHubsInfo; + @GuardedBy("mLock") + private List<HubInfo> mHubsInfo; + + @GuardedBy("mLock") + private final ArrayMap<HubEndpointInfo.HubEndpointIdentifier, HubEndpointInfo> + mHubEndpointInfos = new ArrayMap<>(); HubInfoRegistry(IContextHubWrapper contextHubWrapper) { - List<HubInfo> hubInfos; mContextHubWrapper = contextHubWrapper; + refreshCachedHubs(); + refreshCachedEndpoints(); + } + + /** Retrieve the list of hubs available. */ + List<HubInfo> getHubs() { + synchronized (mLock) { + return mHubsInfo; + } + } + + private void refreshCachedHubs() { + List<HubInfo> hubInfos; try { hubInfos = mContextHubWrapper.getHubs(); } catch (RemoteException e) { Log.e(TAG, "RemoteException while getting Hub info", e); hubInfos = Collections.emptyList(); } - mHubsInfo = hubInfos; + + synchronized (mLock) { + mHubsInfo = hubInfos; + } } - /** Retrieve the list of hubs available. */ - List<HubInfo> getHubs() { - return mHubsInfo; + private void refreshCachedEndpoints() { + List<HubEndpointInfo> endpointInfos; + try { + endpointInfos = mContextHubWrapper.getEndpoints(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException while getting Hub info", e); + endpointInfos = Collections.emptyList(); + } + + synchronized (mLock) { + mHubEndpointInfos.clear(); + for (HubEndpointInfo endpointInfo : endpointInfos) { + mHubEndpointInfos.put(endpointInfo.getIdentifier(), endpointInfo); + } + } + } + + /** Invoked when HAL restarts */ + public void onHalRestart() { + synchronized (mLock) { + refreshCachedHubs(); + refreshCachedEndpoints(); + } + } + + @Override + public void onEndpointStarted(HubEndpointInfo[] endpointInfos) { + synchronized (mLock) { + for (HubEndpointInfo endpointInfo : endpointInfos) { + mHubEndpointInfos.remove(endpointInfo.getIdentifier()); + mHubEndpointInfos.put(endpointInfo.getIdentifier(), endpointInfo); + } + } + } + + @Override + public void onEndpointStopped( + HubEndpointInfo.HubEndpointIdentifier[] endpointIds, byte reason) { + synchronized (mLock) { + for (HubEndpointInfo.HubEndpointIdentifier endpointId : endpointIds) { + mHubEndpointInfos.remove(endpointId); + } + } + } + + /** Return a list of {@link HubEndpointInfo} that represents endpoints with the matching id. */ + public List<HubEndpointInfo> findEndpoints(long endpointIdQuery) { + List<HubEndpointInfo> searchResult = new ArrayList<>(); + synchronized (mLock) { + for (HubEndpointInfo.HubEndpointIdentifier endpointId : mHubEndpointInfos.keySet()) { + if (endpointId.getEndpoint() == endpointIdQuery) { + searchResult.add(mHubEndpointInfos.get(endpointId)); + } + } + } + return searchResult; + } + + /** + * Return a list of {@link HubEndpointInfo} that represents endpoints with the matching service. + */ + public List<HubEndpointInfo> findEndpointsWithService(String serviceDescriptor) { + List<HubEndpointInfo> searchResult = new ArrayList<>(); + synchronized (mLock) { + for (HubEndpointInfo endpointInfo : mHubEndpointInfos.values()) { + for (HubServiceInfo serviceInfo : endpointInfo.getServiceInfoCollection()) { + if (serviceDescriptor.equals(serviceInfo.getServiceDescriptor())) { + searchResult.add(endpointInfo); + } + } + } + } + return searchResult; } void dump(IndentingPrintWriter ipw) { + synchronized (mLock) { + dumpLocked(ipw); + } + } + + @GuardedBy("mLock") + private void dumpLocked(IndentingPrintWriter ipw) { ipw.println(TAG); ipw.increaseIndent(); + ipw.println("Hubs"); for (HubInfo hubInfo : mHubsInfo) { ipw.println(hubInfo); } ipw.decreaseIndent(); + + ipw.println(); + + ipw.increaseIndent(); + ipw.println("Endpoints"); + for (HubEndpointInfo endpointInfo : mHubEndpointInfos.values()) { + ipw.println(endpointInfo); + } + ipw.decreaseIndent(); + + ipw.println(); } } diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java index 6656a6fe9eb4..9b729eb11eed 100644 --- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java +++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java @@ -19,6 +19,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.chre.flags.Flags; import android.hardware.contexthub.HostEndpointInfo; +import android.hardware.contexthub.HubEndpointInfo; import android.hardware.contexthub.MessageDeliveryStatus; import android.hardware.contexthub.NanSessionRequest; import android.hardware.contexthub.V1_0.ContextHub; @@ -229,6 +230,15 @@ public abstract class IContextHubWrapper { return Collections.emptyList(); } + /** Calls the appropriate getEndpoints function depending on the HAL version. */ + public List<HubEndpointInfo> getEndpoints() throws RemoteException { + return Collections.emptyList(); + } + + /** Calls the appropriate registerEndpointCallback function depending on the HAL version. */ + public void registerEndpointCallback(android.hardware.contexthub.IEndpointCallback cb) + throws RemoteException {} + /** * @return True if this version of the Contexthub HAL supports Location setting notifications. */ @@ -622,6 +632,45 @@ public abstract class IContextHubWrapper { return retVal; } + @Override + public List<HubEndpointInfo> getEndpoints() throws RemoteException { + android.hardware.contexthub.IContextHub hub = getHub(); + if (hub == null) { + return Collections.emptyList(); + } + + List<HubEndpointInfo> retVal = new ArrayList<>(); + final List<android.hardware.contexthub.EndpointInfo> halEndpointInfos = + hub.getEndpoints(); + for (android.hardware.contexthub.EndpointInfo halEndpointInfo : halEndpointInfos) { + /* HAL -> API Type conversion */ + final HubEndpointInfo endpointInfo = new HubEndpointInfo(halEndpointInfo); + if (DEBUG) { + Log.i(TAG, "getEndpoints: endpointInfo=" + endpointInfo); + } + retVal.add(endpointInfo); + } + + if (DEBUG) { + Log.i(TAG, "getEndpoints: total count=" + retVal.size()); + } + return retVal; + } + + @Override + public void registerEndpointCallback(android.hardware.contexthub.IEndpointCallback cb) + throws RemoteException { + android.hardware.contexthub.IContextHub hub = getHub(); + if (hub == null) { + return; + } + + if (DEBUG) { + Log.i(TAG, "registerEndpointCallback: cb=" + cb); + } + hub.registerEndpointCallback(cb); + } + public boolean supportsLocationSettingNotifications() { return true; } diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java index 436acba6e492..fce008c23350 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -17,7 +17,6 @@ package com.android.server.media.projection; import static android.Manifest.permission.MANAGE_MEDIA_PROJECTION; -import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT; import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_CREATED; import static android.app.ActivityManagerInternal.MEDIA_PROJECTION_TOKEN_EVENT_DESTROYED; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; @@ -28,7 +27,6 @@ import static android.media.projection.ReviewGrantedConsentResult.RECORD_CANCEL; import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_DISPLAY; import static android.media.projection.ReviewGrantedConsentResult.RECORD_CONTENT_TASK; import static android.media.projection.ReviewGrantedConsentResult.UNKNOWN; -import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; @@ -41,10 +39,7 @@ import android.app.ActivityManagerInternal; import android.app.ActivityOptions.LaunchCookie; import android.app.AppOpsManager; import android.app.IProcessObserver; -import android.app.KeyguardManager; import android.app.compat.CompatChanges; -import android.app.role.RoleManager; -import android.companion.AssociationRequest; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.ComponentName; @@ -74,7 +69,6 @@ import android.os.PermissionEnforcer; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; -import android.provider.Settings; import android.util.ArrayMap; import android.util.Slog; import android.view.ContentRecordingSession; @@ -85,7 +79,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.server.LocalServices; -import com.android.server.SystemConfig; import com.android.server.SystemService; import com.android.server.Watchdog; import com.android.server.wm.WindowManagerInternal; @@ -140,12 +133,12 @@ public final class MediaProjectionManagerService extends SystemService private final ActivityManagerInternal mActivityManagerInternal; private final PackageManager mPackageManager; private final WindowManagerInternal mWmInternal; - private final KeyguardManager mKeyguardManager; - private final RoleManager mRoleManager; + private final MediaRouter mMediaRouter; private final MediaRouterCallback mMediaRouterCallback; private final MediaProjectionMetricsLogger mMediaProjectionMetricsLogger; + private final MediaProjectionStopController mMediaProjectionStopController; private MediaRouter.RouteInfo mMediaRouteInfo; @GuardedBy("mLock") @@ -175,72 +168,16 @@ public final class MediaProjectionManagerService extends SystemService mMediaRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE); mMediaRouterCallback = new MediaRouterCallback(); mMediaProjectionMetricsLogger = injector.mediaProjectionMetricsLogger(context); - mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); - mKeyguardManager.addKeyguardLockedStateListener( - mContext.getMainExecutor(), this::onKeyguardLockedStateChanged); - mRoleManager = mContext.getSystemService(RoleManager.class); + mMediaProjectionStopController = new MediaProjectionStopController(context, + this::maybeStopMediaProjection); Watchdog.getInstance().addMonitor(this); } - /** - * In order to record the keyguard, the MediaProjection package must be either: - * - a holder of RECORD_SENSITIVE_CONTENT permission, or - * - be one of the bugreport allowlisted packages, or - * - hold the OP_PROJECT_MEDIA AppOp. - */ - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - private boolean canCaptureKeyguard() { - if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) { - return true; - } + private void maybeStopMediaProjection(int reason) { synchronized (mLock) { - if (mProjectionGrant == null || mProjectionGrant.packageName == null) { - return false; - } - boolean disableScreenShareProtections = Settings.Global.getInt( - getContext().getContentResolver(), - DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0) != 0; - if (disableScreenShareProtections) { - Slog.v(TAG, - "Allowing keyguard capture as screenshare protections are disabled."); - return true; - } - - if (mPackageManager.checkPermission(RECORD_SENSITIVE_CONTENT, - mProjectionGrant.packageName) - == PackageManager.PERMISSION_GRANTED) { - Slog.v(TAG, - "Allowing keyguard capture for package with RECORD_SENSITIVE_CONTENT " - + "permission"); - return true; - } - if (AppOpsManager.MODE_ALLOWED == mAppOps.noteOpNoThrow(AppOpsManager.OP_PROJECT_MEDIA, - mProjectionGrant.uid, mProjectionGrant.packageName, /* attributionTag= */ null, - "recording lockscreen")) { - // Some tools use media projection by granting the OP_PROJECT_MEDIA app - // op via a shell command. Those tools can be granted keyguard capture - Slog.v(TAG, - "Allowing keyguard capture for package with OP_PROJECT_MEDIA AppOp "); - return true; - } - if (isProjectionAppHoldingAppStreamingRoleLocked()) { - Slog.v(TAG, - "Allowing keyguard capture for package holding app streaming role."); - return true; - } - return SystemConfig.getInstance().getBugreportWhitelistedPackages() - .contains(mProjectionGrant.packageName); - } - } - - @VisibleForTesting - void onKeyguardLockedStateChanged(boolean isKeyguardLocked) { - if (!isKeyguardLocked) return; - synchronized (mLock) { - if (mProjectionGrant != null && !canCaptureKeyguard() - && mProjectionGrant.mVirtualDisplayId != INVALID_DISPLAY) { - Slog.d(TAG, "Content Recording: Stopped MediaProjection" - + " due to keyguard lock"); + if (!mMediaProjectionStopController.isExemptFromStopping(mProjectionGrant, reason)) { + Slog.d(TAG, "Content Recording: Stopping MediaProjection due to " + + MediaProjectionStopController.stopReasonToString(reason)); mProjectionGrant.stop(); } } @@ -310,6 +247,8 @@ public final class MediaProjectionManagerService extends SystemService } }); } + + mMediaProjectionStopController.startTrackingStopReasons(mContext); } @Override @@ -736,20 +675,6 @@ public final class MediaProjectionManagerService extends SystemService } } - /** - * Application holding the app streaming role - * ({@value AssociationRequest#DEVICE_PROFILE_APP_STREAMING}) are allowed to record the - * lockscreen. - * - * @return true if the is held by the recording application. - */ - @GuardedBy("mLock") - private boolean isProjectionAppHoldingAppStreamingRoleLocked() { - return mRoleManager.getRoleHoldersAsUser(AssociationRequest.DEVICE_PROFILE_APP_STREAMING, - mContext.getUser()) - .contains(mProjectionGrant.packageName); - } - private void dump(final PrintWriter pw) { pw.println("MEDIA PROJECTION MANAGER (dumpsys media_projection)"); synchronized (mLock) { @@ -957,18 +882,19 @@ public final class MediaProjectionManagerService extends SystemService public void requestConsentForInvalidProjection(@NonNull IMediaProjection projection) { requestConsentForInvalidProjection_enforcePermission(); - if (android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions() - && mKeyguardManager.isKeyguardLocked()) { - Slog.v(TAG, "Reusing token: Won't request consent while the keyguard is locked"); - return; - } - synchronized (mLock) { if (!isCurrentProjection(projection)) { Slog.v(TAG, "Reusing token: Won't request consent again for a token that " + "isn't current"); return; } + + if (mMediaProjectionStopController.isStartForbidden(mProjectionGrant)) { + Slog.v(TAG, + "Reusing token: Won't request consent while MediaProjection is " + + "restricted"); + return; + } } // Remove calling app identity before performing any privileged operations. @@ -1076,7 +1002,6 @@ public final class MediaProjectionManagerService extends SystemService } } - @VisibleForTesting final class MediaProjection extends IMediaProjection.Stub { // Host app has 5 minutes to begin using the token before it is invalid. // Some apps show a dialog for the user to interact with (selecting recording resolution) @@ -1347,6 +1272,10 @@ public final class MediaProjectionManagerService extends SystemService return mDisplayId; } + long getCreateTimeMillis() { + return mCreateTimeMs; + } + @android.annotation.EnforcePermission(android.Manifest.permission.MANAGE_MEDIA_PROJECTION) @Override public boolean isValid() { @@ -1381,12 +1310,15 @@ public final class MediaProjectionManagerService extends SystemService @Override public void notifyVirtualDisplayCreated(int displayId) { notifyVirtualDisplayCreated_enforcePermission(); - if (mKeyguardManager.isKeyguardLocked() && !canCaptureKeyguard()) { - Slog.w(TAG, "Content Recording: Keyguard locked, aborting MediaProjection"); - stop(); - return; - } synchronized (mLock) { + if (mMediaProjectionStopController.isStartForbidden(mProjectionGrant)) { + Slog.w(TAG, + "Content Recording: MediaProjection start disallowed, aborting " + + "MediaProjection"); + stop(); + return; + } + mVirtualDisplayId = displayId; // If prior session was does not have a valid display id, then update the display diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java b/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java new file mode 100644 index 000000000000..c018e6bc1dc7 --- /dev/null +++ b/services/core/java/com/android/server/media/projection/MediaProjectionStopController.java @@ -0,0 +1,239 @@ +/* + * 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.media.projection; + +import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT; +import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS; + +import android.app.AppOpsManager; +import android.app.KeyguardManager; +import android.app.role.RoleManager; +import android.companion.AssociationRequest; +import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.SystemClock; +import android.provider.Settings; +import android.telecom.TelecomManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.util.Slog; +import android.view.Display; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.server.SystemConfig; + +import java.util.function.Consumer; + +/** + * Tracks events that should cause MediaProjection to stop + */ +public class MediaProjectionStopController { + + private static final String TAG = "MediaProjectionStopController"; + @VisibleForTesting + static final int STOP_REASON_UNKNOWN = 0; + @VisibleForTesting + static final int STOP_REASON_KEYGUARD = 1; + @VisibleForTesting + static final int STOP_REASON_CALL_END = 2; + + private final TelephonyCallback mTelephonyCallback = new ProjectionTelephonyCallback(); + private final Consumer<Integer> mStopReasonConsumer; + private final KeyguardManager mKeyguardManager; + private final TelecomManager mTelecomManager; + private final TelephonyManager mTelephonyManager; + private final AppOpsManager mAppOpsManager; + private final PackageManager mPackageManager; + private final RoleManager mRoleManager; + private final ContentResolver mContentResolver; + + private boolean mIsInCall; + private long mLastCallStartTimeMillis; + + public MediaProjectionStopController(Context context, Consumer<Integer> stopReasonConsumer) { + mStopReasonConsumer = stopReasonConsumer; + mKeyguardManager = context.getSystemService(KeyguardManager.class); + mTelecomManager = context.getSystemService(TelecomManager.class); + mTelephonyManager = context.getSystemService(TelephonyManager.class); + mAppOpsManager = context.getSystemService(AppOpsManager.class); + mPackageManager = context.getPackageManager(); + mRoleManager = context.getSystemService(RoleManager.class); + mContentResolver = context.getContentResolver(); + } + + /** + * Start tracking stop reasons that may interrupt a MediaProjection session. + */ + public void startTrackingStopReasons(Context context) { + final long token = Binder.clearCallingIdentity(); + try { + mKeyguardManager.addKeyguardLockedStateListener(context.getMainExecutor(), + this::onKeyguardLockedStateChanged); + if (com.android.media.projection.flags.Flags.stopMediaProjectionOnCallEnd()) { + callStateChanged(); + mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(), + mTelephonyCallback); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + /** + * Checks whether the given projection grant is exempt from stopping restrictions. + */ + public boolean isExemptFromStopping( + MediaProjectionManagerService.MediaProjection projectionGrant, int stopReason) { + return isExempt(projectionGrant, stopReason, false); + } + + /** + * Apps may disregard recording restrictions via MediaProjection for any stop reason if: + * - the "Disable Screenshare protections" developer option is enabled + * - the app is a holder of RECORD_SENSITIVE_CONTENT permission + * - the app holds the OP_PROJECT_MEDIA AppOp + * - the app holds the COMPANION_DEVICE_APP_STREAMING role + * - the app is one of the bugreport allowlisted packages + * - the current projection does not have an active VirtualDisplay associated with the + * MediaProjection session + */ + private boolean isExempt( + MediaProjectionManagerService.MediaProjection projectionGrant, int stopReason, + boolean forStart) { + if (projectionGrant == null || projectionGrant.packageName == null) { + return true; + } + boolean disableScreenShareProtections = Settings.Global.getInt(mContentResolver, + DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0) != 0; + if (disableScreenShareProtections) { + Slog.v(TAG, "Continuing MediaProjection as screenshare protections are disabled."); + return true; + } + + if (mPackageManager.checkPermission(RECORD_SENSITIVE_CONTENT, projectionGrant.packageName) + == PackageManager.PERMISSION_GRANTED) { + Slog.v(TAG, + "Continuing MediaProjection for package with RECORD_SENSITIVE_CONTENT " + + "permission"); + return true; + } + if (AppOpsManager.MODE_ALLOWED == mAppOpsManager.noteOpNoThrow( + AppOpsManager.OP_PROJECT_MEDIA, projectionGrant.uid, + projectionGrant.packageName, /* attributionTag= */ null, "recording lockscreen")) { + // Some tools use media projection by granting the OP_PROJECT_MEDIA app + // op via a shell command. + Slog.v(TAG, "Continuing MediaProjection for package with OP_PROJECT_MEDIA AppOp "); + return true; + } + if (mRoleManager.getRoleHoldersAsUser(AssociationRequest.DEVICE_PROFILE_APP_STREAMING, + projectionGrant.userHandle).contains(projectionGrant.packageName)) { + Slog.v(TAG, "Continuing MediaProjection for package holding app streaming role."); + return true; + } + if (SystemConfig.getInstance().getBugreportWhitelistedPackages().contains( + projectionGrant.packageName)) { + Slog.v(TAG, "Continuing MediaProjection for package allowlisted for bugreporting."); + return true; + } + if (!forStart && projectionGrant.getVirtualDisplayId() == Display.INVALID_DISPLAY) { + Slog.v(TAG, "Continuing MediaProjection as current projection has no VirtualDisplay."); + return true; + } + + if (stopReason == STOP_REASON_CALL_END + && projectionGrant.getCreateTimeMillis() < mLastCallStartTimeMillis) { + Slog.v(TAG, + "Continuing MediaProjection as (phone) call started after MediaProjection was" + + " created."); + return true; + } + + return false; + } + + /** + * @return {@code true} if a MediaProjection session is currently in a restricted state. + */ + public boolean isStartForbidden( + MediaProjectionManagerService.MediaProjection projectionGrant) { + if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) { + return false; + } + + if (!mKeyguardManager.isKeyguardLocked()) { + return false; + } + + if (isExempt(projectionGrant, STOP_REASON_UNKNOWN, true)) { + return false; + } + return true; + } + + @VisibleForTesting + void onKeyguardLockedStateChanged(boolean isKeyguardLocked) { + if (!isKeyguardLocked) return; + if (!android.companion.virtualdevice.flags.Flags.mediaProjectionKeyguardRestrictions()) { + return; + } + mStopReasonConsumer.accept(STOP_REASON_KEYGUARD); + } + + @VisibleForTesting + void callStateChanged() { + if (!com.android.media.projection.flags.Flags.stopMediaProjectionOnCallEnd()) { + return; + } + boolean isInCall = mTelecomManager.isInCall(); + if (isInCall) { + mLastCallStartTimeMillis = SystemClock.uptimeMillis(); + } + if (isInCall == mIsInCall) { + return; + } + + if (mIsInCall && !isInCall) { + mStopReasonConsumer.accept(STOP_REASON_CALL_END); + } + mIsInCall = isInCall; + } + + /** + * @return a String representation of the stop reason interrupting MediaProjection. + */ + public static String stopReasonToString(int stopReason) { + switch (stopReason) { + case STOP_REASON_KEYGUARD -> { + return "STOP_REASON_KEYGUARD"; + } + case STOP_REASON_CALL_END -> { + return "STOP_REASON_CALL_END"; + } + } + return ""; + } + + private final class ProjectionTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.CallStateListener { + @Override + public void onCallStateChanged(int state) { + callStateChanged(); + } + } +} diff --git a/services/core/java/com/android/server/media/quality/MediaQualityService.java b/services/core/java/com/android/server/media/quality/MediaQualityService.java index c5c8a5ea9d82..00bab8af44f3 100644 --- a/services/core/java/com/android/server/media/quality/MediaQualityService.java +++ b/services/core/java/com/android/server/media/quality/MediaQualityService.java @@ -25,11 +25,11 @@ import android.media.quality.IAmbientBacklightCallback; import android.media.quality.IMediaQualityManager; import android.media.quality.IPictureProfileCallback; import android.media.quality.ISoundProfileCallback; -import android.media.quality.MediaQualityContract.PictureQuality; +import android.media.quality.MediaQualityContract; import android.media.quality.ParamCapability; import android.media.quality.PictureProfile; import android.media.quality.SoundProfile; -import android.os.Bundle; +import android.os.PersistableBundle; import android.util.Log; import com.android.server.SystemService; @@ -74,10 +74,10 @@ public class MediaQualityService extends SystemService { SQLiteDatabase db = mMediaQualityDbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); - values.put(PictureQuality.PARAMETER_TYPE, pp.getProfileType()); - values.put(PictureQuality.PARAMETER_NAME, pp.getName()); - values.put(PictureQuality.PARAMETER_PACKAGE, pp.getPackageName()); - values.put(PictureQuality.PARAMETER_INPUT_ID, pp.getInputId()); + values.put(MediaQualityContract.BaseParameters.PARAMETER_TYPE, pp.getProfileType()); + values.put(MediaQualityContract.BaseParameters.PARAMETER_NAME, pp.getName()); + values.put(MediaQualityContract.BaseParameters.PARAMETER_PACKAGE, pp.getPackageName()); + values.put(MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID, pp.getInputId()); values.put(mMediaQualityDbHelper.SETTINGS, bundleToJson(pp.getParameters())); // id is auto-generated by SQLite upon successful insertion of row @@ -98,8 +98,8 @@ public class MediaQualityService extends SystemService { public PictureProfile getPictureProfile(int type, String name) { SQLiteDatabase db = mMediaQualityDbHelper.getReadableDatabase(); - String selection = PictureQuality.PARAMETER_TYPE + " = ? AND " - + PictureQuality.PARAMETER_NAME + " = ?"; + String selection = MediaQualityContract.BaseParameters.PARAMETER_TYPE + " = ? AND " + + MediaQualityContract.BaseParameters.PARAMETER_NAME + " = ?"; String[] selectionArguments = {Integer.toString(type), name}; try ( @@ -127,7 +127,7 @@ public class MediaQualityService extends SystemService { } } - private String bundleToJson(Bundle bundle) { + private String bundleToJson(PersistableBundle bundle) { JSONObject jsonObject = new JSONObject(); if (bundle == null) { return jsonObject.toString(); @@ -142,9 +142,9 @@ public class MediaQualityService extends SystemService { return jsonObject.toString(); } - private Bundle jsonToBundle(String jsonString) { + private PersistableBundle jsonToBundle(String jsonString) { JSONObject jsonObject = null; - Bundle bundle = new Bundle(); + PersistableBundle bundle = new PersistableBundle(); try { jsonObject = new JSONObject(jsonString); @@ -175,26 +175,26 @@ public class MediaQualityService extends SystemService { private String[] getAllPictureProfileColumns() { return new String[]{ - PictureQuality.PARAMETER_ID, - PictureQuality.PARAMETER_TYPE, - PictureQuality.PARAMETER_NAME, - PictureQuality.PARAMETER_INPUT_ID, - PictureQuality.PARAMETER_PACKAGE, + MediaQualityContract.BaseParameters.PARAMETER_ID, + MediaQualityContract.BaseParameters.PARAMETER_TYPE, + MediaQualityContract.BaseParameters.PARAMETER_NAME, + MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID, + MediaQualityContract.BaseParameters.PARAMETER_PACKAGE, mMediaQualityDbHelper.SETTINGS }; } private PictureProfile getPictureProfileFromCursor(Cursor cursor) { - String returnId = cursor.getString( - cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_ID)); - int type = cursor.getInt( - cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_TYPE)); - String name = cursor.getString( - cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_NAME)); - String inputId = cursor.getString( - cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_INPUT_ID)); - String packageName = cursor.getString( - cursor.getColumnIndexOrThrow(PictureQuality.PARAMETER_PACKAGE)); + String returnId = cursor.getString(cursor.getColumnIndexOrThrow( + MediaQualityContract.BaseParameters.PARAMETER_ID)); + int type = cursor.getInt(cursor.getColumnIndexOrThrow( + MediaQualityContract.BaseParameters.PARAMETER_TYPE)); + String name = cursor.getString(cursor.getColumnIndexOrThrow( + MediaQualityContract.BaseParameters.PARAMETER_NAME)); + String inputId = cursor.getString(cursor.getColumnIndexOrThrow( + MediaQualityContract.BaseParameters.PARAMETER_INPUT_ID)); + String packageName = cursor.getString(cursor.getColumnIndexOrThrow( + MediaQualityContract.BaseParameters.PARAMETER_PACKAGE)); String settings = cursor.getString( cursor.getColumnIndexOrThrow(mMediaQualityDbHelper.SETTINGS)); return new PictureProfile(returnId, type, name, inputId, @@ -203,7 +203,7 @@ public class MediaQualityService extends SystemService { @Override public List<PictureProfile> getPictureProfilesByPackage(String packageName) { - String selection = PictureQuality.PARAMETER_PACKAGE + " = ?"; + String selection = MediaQualityContract.BaseParameters.PARAMETER_PACKAGE + " = ?"; String[] selectionArguments = {packageName}; return getPictureProfilesBasedOnConditions(getAllPictureProfileColumns(), selection, selectionArguments); @@ -216,7 +216,7 @@ public class MediaQualityService extends SystemService { @Override public List<String> getPictureProfilePackageNames() { - String [] column = {PictureQuality.PARAMETER_NAME}; + String [] column = {MediaQualityContract.BaseParameters.PARAMETER_NAME}; List<PictureProfile> pictureProfiles = getPictureProfilesBasedOnConditions(column, null, null); List<String> packageNames = new ArrayList<>(); @@ -262,7 +262,7 @@ public class MediaQualityService extends SystemService { // TODO: implement } @Override - public SoundProfile getSoundProfileById(String id) { + public SoundProfile getSoundProfile(int type, String id) { return null; } @Override @@ -313,6 +313,15 @@ public class MediaQualityService extends SystemService { } @Override + public List<String> getSoundProfileAllowList() { + return new ArrayList<>(); + } + + @Override + public void setSoundProfileAllowList(List<String> packages) { + } + + @Override public boolean isSupported() { return false; } diff --git a/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java b/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java index 925ba1752fe2..3e96afe9bee3 100644 --- a/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java +++ b/services/core/java/com/android/server/notification/DefaultDeviceEffectsApplier.java @@ -39,9 +39,11 @@ import android.service.notification.ZenModeConfig.ConfigOrigin; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.Keep; /** Default implementation for {@link DeviceEffectsApplier}. */ -class DefaultDeviceEffectsApplier implements DeviceEffectsApplier { +@Keep +public class DefaultDeviceEffectsApplier implements DeviceEffectsApplier { private static final String TAG = "DeviceEffectsApplier"; private static final String SUPPRESS_AMBIENT_DISPLAY_TOKEN = "DefaultDeviceEffectsApplier:SuppressAmbientDisplay"; @@ -63,10 +65,10 @@ class DefaultDeviceEffectsApplier implements DeviceEffectsApplier { @GuardedBy("mRegisterReceiverLock") private boolean mIsScreenOffReceiverRegistered; - private ZenDeviceEffects mLastAppliedEffects = new ZenDeviceEffects.Builder().build(); + protected ZenDeviceEffects mLastAppliedEffects = new ZenDeviceEffects.Builder().build(); private boolean mPendingNightMode; - DefaultDeviceEffectsApplier(Context context) { + public DefaultDeviceEffectsApplier(Context context) { mContext = context; mColorDisplayManager = context.getSystemService(ColorDisplayManager.class); mKeyguardManager = context.getSystemService(KeyguardManager.class); @@ -79,56 +81,69 @@ class DefaultDeviceEffectsApplier implements DeviceEffectsApplier { @Override public void apply(ZenDeviceEffects effects, @ConfigOrigin int origin) { - Binder.withCleanCallingIdentity(() -> { - if (mLastAppliedEffects.shouldSuppressAmbientDisplay() - != effects.shouldSuppressAmbientDisplay()) { - try { - traceApplyDeviceEffect("suppressAmbientDisplay", - effects.shouldSuppressAmbientDisplay()); - mPowerManager.suppressAmbientDisplay(SUPPRESS_AMBIENT_DISPLAY_TOKEN, - effects.shouldSuppressAmbientDisplay()); - } catch (Exception e) { - Slog.e(TAG, "Could not change AOD override", e); - } - } + Binder.withCleanCallingIdentity( + () -> { + maybeSuppressAmbientDisplay(effects.shouldSuppressAmbientDisplay()); + maybeDisplayGrayscale(effects.shouldDisplayGrayscale()); + maybeDimWallpaper(effects.shouldDimWallpaper()); + maybeUseNightMode(effects.shouldUseNightMode(), origin); + }); - if (mLastAppliedEffects.shouldDisplayGrayscale() != effects.shouldDisplayGrayscale()) { - if (mColorDisplayManager != null) { - try { - traceApplyDeviceEffect("displayGrayscale", - effects.shouldDisplayGrayscale()); - mColorDisplayManager.setSaturationLevel( - effects.shouldDisplayGrayscale() ? SATURATION_LEVEL_GRAYSCALE - : SATURATION_LEVEL_FULL_COLOR); - } catch (Exception e) { - Slog.e(TAG, "Could not change grayscale override", e); - } - } + mLastAppliedEffects = effects; + } + + protected void maybeSuppressAmbientDisplay(boolean shouldSuppressAmbientDisplay) { + if (mLastAppliedEffects.shouldSuppressAmbientDisplay() != shouldSuppressAmbientDisplay) { + try { + traceApplyDeviceEffect("suppressAmbientDisplay", shouldSuppressAmbientDisplay); + mPowerManager.suppressAmbientDisplay( + SUPPRESS_AMBIENT_DISPLAY_TOKEN, shouldSuppressAmbientDisplay); + } catch (Exception e) { + Slog.e(TAG, "Could not change AOD override", e); } + } + } - if (mLastAppliedEffects.shouldDimWallpaper() != effects.shouldDimWallpaper()) { - if (mWallpaperManager != null) { - try { - traceApplyDeviceEffect("dimWallpaper", effects.shouldDimWallpaper()); - mWallpaperManager.setWallpaperDimAmount( - effects.shouldDimWallpaper() ? WALLPAPER_DIM_AMOUNT_DIMMED - : WALLPAPER_DIM_AMOUNT_NORMAL); - } catch (Exception e) { - Slog.e(TAG, "Could not change wallpaper override", e); - } + protected void maybeDisplayGrayscale(boolean shouldDisplayGrayscale) { + if (mLastAppliedEffects.shouldDisplayGrayscale() != shouldDisplayGrayscale) { + if (mColorDisplayManager != null) { + try { + traceApplyDeviceEffect("displayGrayscale", shouldDisplayGrayscale); + mColorDisplayManager.setSaturationLevel( + shouldDisplayGrayscale + ? SATURATION_LEVEL_GRAYSCALE + : SATURATION_LEVEL_FULL_COLOR); + } catch (Exception e) { + Slog.e(TAG, "Could not change grayscale override", e); } } + } + } - if (mLastAppliedEffects.shouldUseNightMode() != effects.shouldUseNightMode()) { + protected void maybeDimWallpaper(boolean shouldDimWallpaper) { + if (mLastAppliedEffects.shouldDimWallpaper() != shouldDimWallpaper) { + if (mWallpaperManager != null) { try { - updateOrScheduleNightMode(effects.shouldUseNightMode(), origin); + traceApplyDeviceEffect("dimWallpaper", shouldDimWallpaper); + mWallpaperManager.setWallpaperDimAmount( + shouldDimWallpaper + ? WALLPAPER_DIM_AMOUNT_DIMMED + : WALLPAPER_DIM_AMOUNT_NORMAL); } catch (Exception e) { - Slog.e(TAG, "Could not change dark theme override", e); + Slog.e(TAG, "Could not change wallpaper override", e); } } - }); + } + } - mLastAppliedEffects = effects; + protected void maybeUseNightMode(boolean shouldUseNightMode, @ConfigOrigin int origin) { + if (mLastAppliedEffects.shouldUseNightMode() != shouldUseNightMode) { + try { + updateOrScheduleNightMode(shouldUseNightMode, origin); + } catch (Exception e) { + Slog.e(TAG, "Could not change dark theme override", e); + } + } } private void updateOrScheduleNightMode(boolean useNightMode, @ConfigOrigin int origin) { diff --git a/services/core/java/com/android/server/notification/GroupHelper.java b/services/core/java/com/android/server/notification/GroupHelper.java index 5914dbe44b0b..7fd962003ce9 100644 --- a/services/core/java/com/android/server/notification/GroupHelper.java +++ b/services/core/java/com/android/server/notification/GroupHelper.java @@ -92,10 +92,16 @@ public class GroupHelper { static final int REGROUP_REASON_CHANNEL_UPDATE = 0; // Regrouping needed because of notification bundling static final int REGROUP_REASON_BUNDLE = 1; + // Regrouping needed because of notification unbundling + static final int REGROUP_REASON_UNBUNDLE = 2; + // Regrouping needed because of notification unbundling + the original group summary exists + static final int REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP = 3; @IntDef(prefix = { "REGROUP_REASON_" }, value = { REGROUP_REASON_CHANNEL_UPDATE, REGROUP_REASON_BUNDLE, + REGROUP_REASON_UNBUNDLE, + REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP, }) @Retention(RetentionPolicy.SOURCE) @interface RegroupingReason {} @@ -103,7 +109,6 @@ public class GroupHelper { private final Callback mCallback; private final int mAutoGroupAtCount; private final int mAutogroupSparseGroupsAtCount; - private final int mAutoGroupRegroupingAtCount; private final Context mContext; private final PackageManager mPackageManager; private boolean mIsTestHarnessExempted; @@ -190,11 +195,6 @@ public class GroupHelper { mContext = context; mPackageManager = packageManager; mAutogroupSparseGroupsAtCount = autoGroupSparseGroupsAtCount; - if (notificationRegroupOnClassification()) { - mAutoGroupRegroupingAtCount = 1; - } else { - mAutoGroupRegroupingAtCount = mAutoGroupAtCount; - } NOTIFICATION_SHADE_SECTIONS = getNotificationShadeSections(); } @@ -797,7 +797,8 @@ public class GroupHelper { Slog.v(TAG, "isGroupChildInDifferentBundleThanSummary: " + record); } moveNotificationsToNewSection(record.getUserId(), pkgName, - List.of(new NotificationMoveOp(record, null, fullAggregateGroupKey))); + List.of(new NotificationMoveOp(record, null, fullAggregateGroupKey)), + REGROUP_REASON_BUNDLE); return; } } @@ -945,6 +946,27 @@ public class GroupHelper { } } + /** + * Called when a notification that was classified (bundled) is restored to its original channel. + * The notification will be restored to its original group, if any/if summary still exists. + * Otherwise it will be moved to the appropriate section as an ungrouped notification. + * + * @param record the notification which had its channel updated + * @param originalSummaryExists the original group summary exists + */ + @FlaggedApi(android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING) + public void onNotificationUnbundled(final NotificationRecord record, + final boolean originalSummaryExists) { + synchronized (mAggregatedNotifications) { + ArrayMap<String, NotificationRecord> notificationsToCheck = new ArrayMap<>(); + notificationsToCheck.put(record.getKey(), record); + regroupNotifications(record.getUserId(), record.getSbn().getPackageName(), + notificationsToCheck, + originalSummaryExists ? REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP + : REGROUP_REASON_UNBUNDLE); + } + } + @GuardedBy("mAggregatedNotifications") private void regroupNotifications(int userId, String pkgName, ArrayMap<String, NotificationRecord> notificationsToCheck, @@ -973,7 +995,7 @@ public class GroupHelper { // Batch move to new section if (!notificationsToMove.isEmpty()) { - moveNotificationsToNewSection(userId, pkgName, notificationsToMove); + moveNotificationsToNewSection(userId, pkgName, notificationsToMove, regroupingReason); } } @@ -1093,7 +1115,7 @@ public class GroupHelper { @GuardedBy("mAggregatedNotifications") private void moveNotificationsToNewSection(final int userId, final String pkgName, - final List<NotificationMoveOp> notificationsToMove) { + final List<NotificationMoveOp> notificationsToMove, int regroupingReason) { record GroupUpdateOp(FullyQualifiedGroupKey groupKey, NotificationRecord record, boolean hasSummary) { } // Bundled operations to apply to groups affected by the channel update @@ -1111,7 +1133,8 @@ public class GroupHelper { if (DEBUG) { Log.i(TAG, "moveNotificationToNewSection: " + record + " " + newFullAggregateGroupKey - + " from: " + oldFullAggregateGroupKey); + + " from: " + oldFullAggregateGroupKey + " regroupingReason: " + + regroupingReason); } // Update/remove aggregate summary for old group @@ -1140,28 +1163,35 @@ public class GroupHelper { // Add moved notifications to the ungrouped list for new group and do grouping // after all notifications have been handled if (newFullAggregateGroupKey != null) { - final ArrayMap<String, NotificationAttributes> newAggregatedNotificationsAttrs = + if (notificationRegroupOnClassification() + && regroupingReason == REGROUP_REASON_UNBUNDLE_ORIGINAL_GROUP) { + // Just reset override group key, original summary exists + // => will be grouped back to its original group + record.setOverrideGroupKey(null); + } else { + final ArrayMap<String, NotificationAttributes> newAggregatedNotificationsAttrs = mAggregatedNotifications.getOrDefault(newFullAggregateGroupKey, new ArrayMap<>()); - boolean hasSummary = !newAggregatedNotificationsAttrs.isEmpty(); - ArrayMap<String, NotificationAttributes> ungrouped = + boolean hasSummary = !newAggregatedNotificationsAttrs.isEmpty(); + ArrayMap<String, NotificationAttributes> ungrouped = mUngroupedAbuseNotifications.getOrDefault(newFullAggregateGroupKey, new ArrayMap<>()); - ungrouped.put(record.getKey(), new NotificationAttributes( + ungrouped.put(record.getKey(), new NotificationAttributes( record.getFlags(), record.getNotification().getSmallIcon(), record.getNotification().color, record.getNotification().visibility, record.getNotification().getGroupAlertBehavior(), record.getChannel().getId())); - mUngroupedAbuseNotifications.put(newFullAggregateGroupKey, ungrouped); + mUngroupedAbuseNotifications.put(newFullAggregateGroupKey, ungrouped); - record.setOverrideGroupKey(null); + record.setOverrideGroupKey(null); - // Only add once, for triggering notification - if (!groupsToUpdate.containsKey(newFullAggregateGroupKey)) { - groupsToUpdate.put(newFullAggregateGroupKey, - new GroupUpdateOp(newFullAggregateGroupKey, record, hasSummary)); + // Only add once, for triggering notification + if (!groupsToUpdate.containsKey(newFullAggregateGroupKey)) { + groupsToUpdate.put(newFullAggregateGroupKey, + new GroupUpdateOp(newFullAggregateGroupKey, record, hasSummary)); + } } } } @@ -1176,7 +1206,7 @@ public class GroupHelper { NotificationRecord triggeringNotification = groupsToUpdate.get(groupKey).record; boolean hasSummary = groupsToUpdate.get(groupKey).hasSummary; //Group needs to be created/updated - if (ungrouped.size() >= mAutoGroupRegroupingAtCount + if (ungrouped.size() >= mAutoGroupAtCount || (hasSummary && !aggregatedNotificationsAttrs.isEmpty())) { NotificationSectioner sectioner = getSection(triggeringNotification); if (sectioner == null) { @@ -1436,7 +1466,8 @@ public class GroupHelper { } } - private ArrayMap<String, NotificationRecord> getSparseGroups( + @VisibleForTesting + protected ArrayMap<String, NotificationRecord> getSparseGroups( final FullyQualifiedGroupKey fullAggregateGroupKey, final List<NotificationRecord> notificationList, final Map<String, NotificationRecord> summaryByGroupKey, @@ -1448,8 +1479,8 @@ public class GroupHelper { && summary.getUserId() == fullAggregateGroupKey.userId && summary.getSbn().isAppGroup() && !summary.getGroupKey().equals(fullAggregateGroupKey.toString())) { - int numChildren = getNumChildrenForGroup(summary.getSbn().getGroup(), - notificationList); + int numChildren = getNumChildrenForGroupWithSection(summary.getSbn().getGroup(), + notificationList, sectioner); if (numChildren > 0 && numChildren < MIN_CHILD_COUNT_TO_AVOID_FORCE_GROUPING) { sparseGroups.put(summary.getGroupKey(), summary); } @@ -1459,6 +1490,43 @@ public class GroupHelper { return sparseGroups; } + /** + * Get the number of children of a group if all match a certain section. + * Used for force grouping sparse groups, where the summary may match a section but the + * child notifications do not: ie. conversations + * + * @param groupKey the group key (name) + * @param notificationList all notifications list + * @param sectioner the section to match + * @return number of children in that group or -1 if section does not match + */ + private int getNumChildrenForGroupWithSection(final String groupKey, + final List<NotificationRecord> notificationList, + final NotificationSectioner sectioner) { + int numChildren = 0; + for (NotificationRecord r : notificationList) { + if (!r.getNotification().isGroupSummary() && groupKey.equals(r.getSbn().getGroup())) { + NotificationSectioner childSection = getSection(r); + if (childSection == null || childSection != sectioner) { + if (DEBUG) { + Slog.i(TAG, + "getNumChildrenForGroupWithSection skip because invalid section: " + + groupKey + " r: " + r); + } + return -1; + } else { + numChildren++; + } + } + } + + if (DEBUG) { + Slog.i(TAG, + "getNumChildrenForGroupWithSection " + groupKey + " numChild: " + numChildren); + } + return numChildren; + } + @GuardedBy("mAggregatedNotifications") private void cacheCanceledSummary(NotificationRecord record) { final FullyQualifiedGroupKey groupKey = new FullyQualifiedGroupKey(record.getUserId(), diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 0d8880af2256..5182dfe60fcc 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -7180,13 +7180,16 @@ public class NotificationManagerService extends SystemService { Slog.i(TAG, "Removing app summary (all children bundled): " + groupSummary); } - canceledSummary = groupSummary; - mSummaryByGroupKey.remove(oldGroupKey); - cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), + if (convertSummaryToNotificationLocked(groupSummary.getKey())) { + groupSummary.isCanceled = true; + canceledSummary = groupSummary; + mSummaryByGroupKey.remove(oldGroupKey); + cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), groupSummary.getSbn().getPackageName(), groupSummary.getSbn().getTag(), groupSummary.getSbn().getId(), 0, 0, false, groupSummary.getUserId(), NotificationListenerService.REASON_GROUP_OPTIMIZATION, null); + } } } } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index ca4f83fd46f6..81dc38a02191 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -1015,7 +1015,13 @@ public class ZenModeHelper { private static void applyConditionAndReconsiderOverride(ZenRule rule, Condition condition, int origin) { if (Flags.modesApi() && Flags.modesUi()) { - if (origin == ORIGIN_USER_IN_SYSTEMUI && condition != null + if (isImplicitRuleId(rule.id)) { + // Implicit rules do not use overrides, and always apply conditions directly. + // This is compatible with the previous behavior (where the package set the + // interruption filter, and no "snoozing" took place if the user changed it later). + rule.condition = condition; + rule.resetConditionOverride(); + } else if (origin == ORIGIN_USER_IN_SYSTEMUI && condition != null && condition.source == SOURCE_USER_ACTION) { // Apply as override, instead of actual condition. // If the new override is the reverse of a previous (still active) override, try diff --git a/services/core/java/com/android/server/pm/BroadcastHelper.java b/services/core/java/com/android/server/pm/BroadcastHelper.java index 9f4b9f1c1f24..6d54be84d5e5 100644 --- a/services/core/java/com/android/server/pm/BroadcastHelper.java +++ b/services/core/java/com/android/server/pm/BroadcastHelper.java @@ -58,6 +58,7 @@ import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.provider.DeviceConfig; import android.stats.storage.StorageEnums; +import android.text.TextUtils; import android.util.IntArray; import android.util.Log; import android.util.Pair; @@ -355,7 +356,8 @@ public final class BroadcastHelper { @Nullable int[] userIds, @Nullable int[] instantUserIds, @Nullable SparseArray<int[]> broadcastAllowList, - @NonNull AndroidPackage pkg) { + @NonNull AndroidPackage pkg, + @NonNull String[] sharedUidPackages) { final boolean isForWholeApp = componentNames.contains(packageName); if (isForWholeApp || !android.content.pm.Flags.reduceBroadcastsForComponentStateChanges()) { sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, componentNames, @@ -374,20 +376,36 @@ public final class BroadcastHelper { exportedComponentNames.removeAll(notExportedComponentNames); if (!notExportedComponentNames.isEmpty()) { - // Limit sending of the PACKAGE_CHANGED broadcast to only the system and the - // application itself when the component is not exported. + // Limit sending of the PACKAGE_CHANGED broadcast to only the system, the application + // itself and applications with the same UID when the component is not exported. // First, send the PACKAGE_CHANGED broadcast to the system. - sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, - notExportedComponentNames, packageUid, reason, userIds, instantUserIds, - broadcastAllowList, "android" /* targetPackageName */, - new String[]{PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED}); + if (!TextUtils.equals(packageName, "android")) { + sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, + notExportedComponentNames, packageUid, reason, userIds, instantUserIds, + broadcastAllowList, "android" /* targetPackageName */, + new String[]{ + PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED}); + } // Second, send the PACKAGE_CHANGED broadcast to the application itself. sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, notExportedComponentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, packageName /* targetPackageName */, null /* requiredPermissions */); + + // Third, send the PACKAGE_CHANGED broadcast to the applications with the same UID. + for (int i = 0; i < sharedUidPackages.length; i++) { + final String sharedPackage = sharedUidPackages[i]; + if (TextUtils.equals(packageName, sharedPackage)) { + continue; + } + sendPackageChangedBroadcastWithPermissions(packageName, dontKillApp, + notExportedComponentNames, packageUid, reason, userIds, instantUserIds, + broadcastAllowList, sharedPackage /* targetPackageName */, + null /* requiredPermissions */); + } + } if (!exportedComponentNames.isEmpty()) { @@ -936,7 +954,8 @@ public final class BroadcastHelper { isInstantApp ? null : snapshot.getVisibilityAllowLists(packageName, userIds); mHandler.post(() -> sendPackageChangedBroadcastInternal( packageName, dontKillApp, componentNames, packageUid, reason, userIds, - instantUserIds, broadcastAllowList, setting.getPkg())); + instantUserIds, broadcastAllowList, setting.getPkg(), + snapshot.getSharedUserPackagesForPackage(packageName, userId))); mPackageMonitorCallbackHelper.notifyPackageChanged(packageName, dontKillApp, componentNames, packageUid, reason, userIds, instantUserIds, broadcastAllowList, mHandler); } diff --git a/services/core/java/com/android/server/pm/InstallDependencyHelper.java b/services/core/java/com/android/server/pm/InstallDependencyHelper.java index 745665bab5b3..527d68049537 100644 --- a/services/core/java/com/android/server/pm/InstallDependencyHelper.java +++ b/services/core/java/com/android/server/pm/InstallDependencyHelper.java @@ -17,51 +17,240 @@ package com.android.server.pm; import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY; +import static android.os.Process.SYSTEM_UID; +import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; import android.content.pm.SharedLibraryInfo; +import android.content.pm.dependencyinstaller.DependencyInstallerCallback; +import android.content.pm.dependencyinstaller.IDependencyInstallerCallback; +import android.content.pm.dependencyinstaller.IDependencyInstallerService; import android.content.pm.parsing.PackageLite; +import android.os.Handler; import android.os.OutcomeReceiver; +import android.os.Process; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.infra.AndroidFuture; +import com.android.internal.infra.ServiceConnector; import java.util.List; +import java.util.concurrent.TimeUnit; /** * Helper class to interact with SDK Dependency Installer service. */ public class InstallDependencyHelper { + private static final String TAG = InstallDependencyHelper.class.getSimpleName(); + private static final boolean DEBUG = true; + private static final String ACTION_INSTALL_DEPENDENCY = + "android.intent.action.INSTALL_DEPENDENCY"; + // The maximum amount of time to wait before the system unbinds from the verifier. + private static final long UNBIND_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(6); + private static final long REQUEST_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(1); + private final SharedLibrariesImpl mSharedLibraries; + private final Context mContext; + private final Object mRemoteServiceLock = new Object(); + + @GuardedBy("mRemoteServiceLock") + private ServiceConnector<IDependencyInstallerService> mRemoteService = null; - InstallDependencyHelper(SharedLibrariesImpl sharedLibraries) { + InstallDependencyHelper(Context context, SharedLibrariesImpl sharedLibraries) { + mContext = context; mSharedLibraries = sharedLibraries; } - void resolveLibraryDependenciesIfNeeded(PackageLite pkg, - OutcomeReceiver<Void, PackageManagerException> callback) { - final List<SharedLibraryInfo> missing; + void resolveLibraryDependenciesIfNeeded(PackageLite pkg, Computer snapshot, int userId, + Handler handler, OutcomeReceiver<Void, PackageManagerException> origCallback) { + CallOnceProxy callback = new CallOnceProxy(handler, origCallback); try { - missing = mSharedLibraries.collectMissingSharedLibraryInfos(pkg); + resolveLibraryDependenciesIfNeededInternal(pkg, snapshot, userId, handler, callback); } catch (PackageManagerException e) { callback.onError(e); - return; + } catch (Exception e) { + onError(callback, e.getMessage()); } + } + + + private void resolveLibraryDependenciesIfNeededInternal(PackageLite pkg, Computer snapshot, + int userId, Handler handler, CallOnceProxy callback) throws PackageManagerException { + final List<SharedLibraryInfo> missing = + mSharedLibraries.collectMissingSharedLibraryInfos(pkg); if (missing.isEmpty()) { + if (DEBUG) { + Slog.i(TAG, "No missing dependency for " + pkg); + } // No need for dependency resolution. Move to installation directly. callback.onResult(null); return; } - try { - bindToDependencyInstaller(); - } catch (Exception e) { - PackageManagerException pe = new PackageManagerException( - INSTALL_FAILED_MISSING_SHARED_LIBRARY, e.getMessage()); - callback.onError(pe); + if (!bindToDependencyInstallerIfNeeded(userId, handler, snapshot)) { + onError(callback, "Dependency Installer Service not found"); + return; + } + + IDependencyInstallerCallback serviceCallback = new IDependencyInstallerCallback.Stub() { + @Override + public void onAllDependenciesResolved(int[] sessionIds) throws RemoteException { + // TODO(b/372862145): Implement waiting for sessions to finish installation + callback.onResult(null); + } + + @Override + public void onFailureToResolveAllDependencies() throws RemoteException { + onError(callback, "Failed to resolve all dependencies automatically"); + } + }; + + boolean scheduleSuccess; + synchronized (mRemoteServiceLock) { + scheduleSuccess = mRemoteService.run(service -> { + service.onDependenciesRequired(missing, + new DependencyInstallerCallback(serviceCallback.asBinder())); + }); + } + if (!scheduleSuccess) { + onError(callback, "Failed to schedule job on Dependency Installer Service"); } } - private void bindToDependencyInstaller() { - throw new IllegalStateException("Failed to bind to Dependency Installer"); + private void onError(CallOnceProxy callback, String msg) { + PackageManagerException pe = new PackageManagerException( + INSTALL_FAILED_MISSING_SHARED_LIBRARY, msg); + callback.onError(pe); } + private boolean bindToDependencyInstallerIfNeeded(int userId, Handler handler, + Computer snapshot) { + synchronized (mRemoteServiceLock) { + if (mRemoteService != null) { + if (DEBUG) { + Slog.i(TAG, "DependencyInstallerService already bound"); + } + return true; + } + } + + Intent serviceIntent = new Intent(ACTION_INSTALL_DEPENDENCY); + // TODO(b/372862145): Use RoleManager to find the package name + List<ResolveInfo> resolvedIntents = snapshot.queryIntentServicesInternal( + serviceIntent, /*resolvedType=*/ null, /*flags=*/0, + userId, SYSTEM_UID, Process.INVALID_PID, + /*includeInstantApps*/ false, /*resolveForStart*/ false); + + if (resolvedIntents.isEmpty()) { + return false; + } + + ResolveInfo resolveInfo = resolvedIntents.getFirst(); + ComponentName componentName = resolveInfo.getComponentInfo().getComponentName(); + serviceIntent.setComponent(componentName); + + ServiceConnector<IDependencyInstallerService> serviceConnector = + new ServiceConnector.Impl<IDependencyInstallerService>(mContext, serviceIntent, + Context.BIND_AUTO_CREATE, userId, + IDependencyInstallerService.Stub::asInterface) { + @Override + protected Handler getJobHandler() { + return handler; + } + + @Override + protected long getRequestTimeoutMs() { + return REQUEST_TIMEOUT_MILLIS; + } + + @Override + protected long getAutoDisconnectTimeoutMs() { + return UNBIND_TIMEOUT_MILLIS; + } + }; + + + synchronized (mRemoteServiceLock) { + // Some other thread managed to connect to the service first + if (mRemoteService != null) { + return true; + } + mRemoteService = serviceConnector; + mRemoteService.setServiceLifecycleCallbacks( + new ServiceConnector.ServiceLifecycleCallbacks<>() { + @Override + public void onDisconnected(@NonNull IDependencyInstallerService service) { + Slog.w(TAG, + "DependencyInstallerService " + componentName + " is disconnected"); + destroy(); + } + + @Override + public void onBinderDied() { + Slog.w(TAG, "DependencyInstallerService " + componentName + " has died"); + destroy(); + } + + private void destroy() { + synchronized (mRemoteServiceLock) { + if (mRemoteService != null) { + mRemoteService.unbind(); + mRemoteService = null; + } + } + } + + }); + AndroidFuture<IDependencyInstallerService> unusedFuture = mRemoteService.connect(); + } + return true; + } + + /** + * Ensure we call one of the outcomes only once, on the right handler. + * + * Repeated calls will be no-op. + */ + private static class CallOnceProxy implements OutcomeReceiver<Void, PackageManagerException> { + private final Handler mHandler; + private final OutcomeReceiver<Void, PackageManagerException> mCallback; + @GuardedBy("this") + private boolean mCalled = false; + + CallOnceProxy(Handler handler, OutcomeReceiver<Void, PackageManagerException> callback) { + mHandler = handler; + mCallback = callback; + } + + @Override + public void onResult(Void result) { + synchronized (this) { + if (!mCalled) { + mHandler.post(() -> { + mCallback.onResult(null); + }); + mCalled = true; + } + } + } + + @Override + public void onError(@NonNull PackageManagerException error) { + synchronized (this) { + if (!mCalled) { + mHandler.post(() -> { + mCallback.onError(error); + }); + mCalled = true; + } + } + } + } } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index d9e76966892c..8168c5493304 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -1029,12 +1029,14 @@ final class InstallPackageHelper { if (reconciledPackages == null) { return; } - if (Flags.improveInstallFreeze()) { - prepPerformDexoptIfNeeded(reconciledPackages); - } - if (renameAndUpdatePaths(requests) - && commitInstallPackages(reconciledPackages)) { - success = true; + if (renameAndUpdatePaths(requests)) { + // rename before dexopt because art will encoded the path in the odex/vdex file + if (Flags.improveInstallFreeze()) { + prepPerformDexoptIfNeeded(reconciledPackages); + } + if (commitInstallPackages(reconciledPackages)) { + success = true; + } } } } finally { diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 2c0942337b1f..286333cb83a9 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -96,7 +96,6 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IInterface; -import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteCallbackList; @@ -2667,6 +2666,7 @@ public class LauncherAppsService extends SystemService { } final String[] packagesNullExtras = packagesWithoutExtras.toArray( new String[packagesWithoutExtras.size()]); + final int n = mListeners.beginBroadcast(); try { for (int i = 0; i < n; i++) { @@ -2852,7 +2852,7 @@ public class LauncherAppsService extends SystemService { class SecureSettingsObserver extends ContentObserver { SecureSettingsObserver() { - super(new Handler(Looper.getMainLooper())); + super(mCallbackHandler); } @Override @@ -2866,32 +2866,29 @@ public class LauncherAppsService extends SystemService { if (privateProfile.getIdentifier() == UserHandle.USER_NULL) { return; } - final int n = mListeners.beginBroadcast(); try { for (int i = 0; i < n; i++) { - final IOnAppsChangedListener listener = - mListeners.getBroadcastItem(i); + final IOnAppsChangedListener listener = mListeners.getBroadcastItem(i); final BroadcastCookie cookie = - (BroadcastCookie) mListeners.getBroadcastCookie( - i); + (BroadcastCookie) mListeners.getBroadcastCookie(i); if (!isEnabledProfileOf(cookie, privateProfile, "onSecureSettingsChange")) { Log.d(TAG, "onSecureSettingsChange: Skipping - profile not enabled" + " or not accessible for package=" + cookie.packageName + ", packageUid=" + cookie.callingUid); - } else { - try { - Log.d(TAG, - "onUserConfigChanged: triggering onUserConfigChanged"); - listener.onUserConfigChanged( - mUserManagerInternal.getLauncherUserInfo( - privateProfile.getIdentifier())); - } catch (RemoteException re) { - Slog.d(TAG, "onUserConfigChanged: Callback failed ", re); - } + continue; + } + try { + Log.d(TAG, "onUserConfigChanged: triggering onUserConfigChanged"); + listener.onUserConfigChanged( + mUserManagerInternal.getLauncherUserInfo( + privateProfile.getIdentifier())); + } catch (RemoteException re) { + Slog.d(TAG, "onUserConfigChanged: Callback failed ", re); } } + } finally { mListeners.finishBroadcast(); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index eb70748918b6..9b44f93467ed 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -347,7 +347,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements synchronized (mVerificationPolicyPerUser) { mVerificationPolicyPerUser.put(USER_SYSTEM, DEFAULT_VERIFICATION_POLICY); } - mInstallDependencyHelper = new InstallDependencyHelper( + mInstallDependencyHelper = new InstallDependencyHelper(mContext, mPm.mInjector.getSharedLibrariesImpl()); LocalServices.getService(SystemServiceManager.class).startService( diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index e156b31c19e1..505b7e6205df 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -3428,8 +3428,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private void resolveLibraryDependenciesIfNeeded() { synchronized (mLock) { - // TODO(b/372862145): Callback should be called on a handler passed as parameter mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(mPackageLite, + mPm.snapshotComputer(), userId, mHandler, new OutcomeReceiver<>() { @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 7ef35829a46e..961b4b3c91e3 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -3606,6 +3606,13 @@ class PackageManagerShellCommand extends ShellCommand { case "--force-verification": sessionParams.setForceVerification(); break; + case "--disable-auto-install-dependencies": + if (Flags.sdkDependencyInstaller()) { + sessionParams.setEnableAutoInstallDependencies(false); + } else { + throw new IllegalArgumentException("Unknown option " + opt); + } + break; default: throw new IllegalArgumentException("Unknown option " + opt); } @@ -4894,6 +4901,10 @@ class PackageManagerShellCommand extends ShellCommand { + "#compiler_filters"); pw.println(" or 'skip'"); pw.println(" --force-verification: if set, enable the verification for this install"); + if (Flags.sdkDependencyInstaller()) { + pw.println(" --disable-auto-install-dependencies: if set, any missing shared"); + pw.println(" library dependencies will not be auto-installed"); + } pw.println(""); pw.println(" install-existing [--user USER_ID|all|current]"); pw.println(" [--instant] [--full] [--wait] [--restrict-permissions] PACKAGE"); diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java index fc54f6864db0..17d7a14d9129 100644 --- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java +++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java @@ -1017,10 +1017,11 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable boolean isSdkOrStatic = libraryType.equals(LIBRARY_TYPE_SDK) || libraryType.equals(LIBRARY_TYPE_STATIC); if (isSdkOrStatic && outMissingSharedLibraryInfos != null) { - // TODO(b/372862145): Pass the CertDigest too // If Dependency Installation is supported, try that instead of failing. + final List<String> libCertDigests = Arrays.asList(requiredCertDigests[i]); SharedLibraryInfo missingLibrary = new SharedLibraryInfo( - libName, libVersion, SharedLibraryInfo.TYPE_SDK_PACKAGE + libName, libVersion, SharedLibraryInfo.TYPE_SDK_PACKAGE, + libCertDigests ); outMissingSharedLibraryInfos.add(missingLibrary); } else { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 06e29c2c1408..b2b8aaf7dd2a 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -4984,7 +4984,10 @@ public class UserManagerService extends IUserManager.Stub { res.getValue(com.android.internal.R.string.owner_name, mOwnerNameTypedValue, true); final CharSequence ownerName = mOwnerNameTypedValue.coerceToString(); mOwnerName.set(ownerName != null ? ownerName.toString() : null); + // Invalidate when owners name changes due to config change. + UserManager.invalidateCacheOnUserDataChanged(); } + } private void scheduleWriteUserList() { @@ -4997,6 +5000,8 @@ public class UserManagerService extends IUserManager.Stub { Message msg = mHandler.obtainMessage(WRITE_USER_LIST_MSG); mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY); } + // Invalidate cache when {@link UserData} changed, but write was scheduled for later. + UserManager.invalidateCacheOnUserDataChanged(); } private void scheduleWriteUser(@UserIdInt int userId) { @@ -5009,6 +5014,8 @@ public class UserManagerService extends IUserManager.Stub { Message msg = mHandler.obtainMessage(WRITE_USER_MSG, userId); mHandler.sendMessageDelayed(msg, WRITE_USER_DELAY); } + // Invalidate cache when {@link Data} changed, but write was scheduled for later. + UserManager.invalidateCacheOnUserDataChanged(); } private ResilientAtomicFile getUserFile(int userId) { @@ -5032,6 +5039,9 @@ public class UserManagerService extends IUserManager.Stub { if (DBG) { debug("writeUserLP " + userData); } + // invalidate caches related to any {@link UserData} change. + UserManager.invalidateCacheOnUserDataChanged(); + try (ResilientAtomicFile userFile = getUserFile(userData.info.id)) { FileOutputStream fos = null; try { @@ -5196,6 +5206,8 @@ public class UserManagerService extends IUserManager.Stub { if (DBG) { debug("writeUserList"); } + // invalidate caches related to any {@link UserData} change. + UserManager.invalidateCacheOnUserDataChanged(); try (ResilientAtomicFile file = getUserListFile()) { FileOutputStream fos = null; @@ -7958,7 +7970,7 @@ public class UserManagerService extends IUserManager.Stub { Settings.Secure.getIntForUser(mContext.getContentResolver(), HIDE_PRIVATESPACE_ENTRY_POINT, parentId) == 1); } catch (Settings.SettingNotFoundException e) { - throw new RuntimeException(e); + config.putBoolean(PRIVATE_SPACE_ENTRYPOINT_HIDDEN, false); } } return new LauncherUserInfo.Builder(userDetails.getName(), diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java index 4f67318faddb..c9f66eb5ccb2 100644 --- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java +++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java @@ -29,6 +29,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; +import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Icon; import android.hardware.input.AppLaunchData; @@ -65,6 +66,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -84,6 +86,7 @@ public class ModifierShortcutManager { private static final String ATTRIBUTE_PACKAGE = "package"; private static final String ATTRIBUTE_CLASS = "class"; private static final String ATTRIBUTE_SHORTCUT = "shortcut"; + private static final String ATTRIBUTE_KEYCODE = "keycode"; private static final String ATTRIBUTE_CATEGORY = "category"; private static final String ATTRIBUTE_SHIFT = "shift"; private static final String ATTRIBUTE_ROLE = "role"; @@ -167,6 +170,9 @@ public class ModifierShortcutManager { }, UserHandle.ALL); mCurrentUser = currentUser; mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); + } + + void onSystemReady() { loadShortcuts(); } @@ -335,6 +341,7 @@ public class ModifierShortcutManager { try { XmlResourceParser parser = mContext.getResources().getXml(R.xml.bookmarks); XmlUtils.beginDocument(parser, TAG_BOOKMARKS); + KeyCharacterMap virtualKcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); while (true) { XmlUtils.nextElement(parser); @@ -353,15 +360,36 @@ public class ModifierShortcutManager { String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY); String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT); String roleName = parser.getAttributeValue(null, ATTRIBUTE_ROLE); + final int keycode; + final int modifierState; + TypedArray a = mContext.getResources().obtainAttributes(parser, + R.styleable.Bookmark); + try { + keycode = a.getInt(R.styleable.Bookmark_keycode, KeyEvent.KEYCODE_UNKNOWN); + modifierState = a.getInt(R.styleable.Bookmark_modifierState, 0); + } finally { + a.recycle(); + } + if (TextUtils.isEmpty(shortcutName) && keycode != KeyEvent.KEYCODE_UNKNOWN) { + // Try to find shortcutChar using keycode + shortcutName = String.valueOf(virtualKcm.getDisplayLabel(keycode)).toLowerCase( + Locale.ROOT); + } if (TextUtils.isEmpty(shortcutName)) { Log.w(TAG, "Shortcut required for bookmark with category=" + categoryName + " packageName=" + packageName + " className=" + className - + " role=" + roleName + "shiftName=" + shiftName); + + " role=" + roleName + " shiftName=" + shiftName + " keycode= " + + keycode + " modifierState= " + modifierState); continue; } - final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true")); + final boolean isShiftShortcut; + if (!TextUtils.isEmpty(shiftName)) { + isShiftShortcut = shiftName.equals("true"); + } else { + isShiftShortcut = (modifierState & KeyEvent.META_SHIFT_ON) != 0; + } if (modifierShortcutManagerRefactor()) { final char shortcutChar = shortcutName.charAt(0); @@ -376,7 +404,7 @@ public class ModifierShortcutManager { bookmark = new RoleBookmark(shortcutChar, isShiftShortcut, roleName); } if (bookmark != null) { - Log.d(TAG, "adding shortcut " + bookmark + "shift=" + Log.d(TAG, "adding shortcut " + bookmark + " shift=" + isShiftShortcut + " char=" + shortcutChar); mBookmarks.put(new Pair<>(shortcutChar, isShiftShortcut), bookmark); } diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index dda5bcf24d07..85e7cfe33c0e 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -6610,6 +6610,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // In normal flow, systemReady is called before other system services are ready. // So it is better not to bind keyguard here. mKeyguardDelegate.onSystemReady(); + mModifierShortcutManager.onSystemReady(); mVrManagerInternal = LocalServices.getService(VrManagerInternal.class); if (mVrManagerInternal != null) { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 0acfe92f578d..37883f594227 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -2332,6 +2332,8 @@ public final class PowerManagerService extends SystemService Trace.traceBegin(Trace.TRACE_TAG_POWER, traceMethodName); try { // Phase 2: Handle wakefulness change and bookkeeping. + // Under lock, invalidate before set ensures caches won't return stale values. + mInjector.invalidateIsInteractiveCaches(); mWakefulnessRaw = newWakefulness; mWakefulnessChanging = true; mDirty |= DIRTY_WAKEFULNESS; @@ -2429,7 +2431,6 @@ public final class PowerManagerService extends SystemService void onPowerGroupEventLocked(int event, PowerGroup powerGroup) { mWakefulnessChanging = true; mDirty |= DIRTY_WAKEFULNESS; - mInjector.invalidateIsInteractiveCaches(); final int groupId = powerGroup.getGroupId(); if (event == DisplayGroupPowerChangeListener.DISPLAY_GROUP_REMOVED) { mPowerGroups.delete(groupId); diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java index 2c0ce252df18..17459df2bc1a 100644 --- a/services/core/java/com/android/server/power/hint/HintManagerService.java +++ b/services/core/java/com/android/server/power/hint/HintManagerService.java @@ -33,11 +33,15 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.hardware.power.ChannelConfig; +import android.hardware.power.CpuHeadroomParams; +import android.hardware.power.GpuHeadroomParams; import android.hardware.power.IPower; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; import android.hardware.power.WorkDuration; import android.os.Binder; +import android.os.CpuHeadroomParamsInternal; +import android.os.GpuHeadroomParamsInternal; import android.os.Handler; import android.os.IBinder; import android.os.IHintManager; @@ -90,6 +94,10 @@ public final class HintManagerService extends SystemService { private static final int EVENT_CLEAN_UP_UID = 3; @VisibleForTesting static final int CLEAN_UP_UID_DELAY_MILLIS = 1000; + private static final int DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS = 1000; + private static final int DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS = 1000; + private static final int HEADROOM_INTERVAL_UNSUPPORTED = -1; + @VisibleForTesting static final int DEFAULT_HEADROOM_PID = -1; @VisibleForTesting final long mHintSessionPreferredRate; @@ -160,10 +168,76 @@ public final class HintManagerService extends SystemService { private static final String PROPERTY_SF_ENABLE_CPU_HINT = "debug.sf.enable_adpf_cpu_hint"; private static final String PROPERTY_HWUI_ENABLE_HINT_MANAGER = "debug.hwui.use_hint_manager"; + private static final String PROPERTY_USE_HAL_HEADROOMS = "persist.hms.use_hal_headrooms"; private Boolean mFMQUsesIntegratedEventFlag = false; - @VisibleForTesting final IHintManager.Stub mService = new BinderService(); + private final Object mCpuHeadroomLock = new Object(); + + private static class CpuHeadroomCacheItem { + long mExpiredTimeMillis; + CpuHeadroomParamsInternal mParams; + float[] mHeadroom; + long mPid; + + CpuHeadroomCacheItem(long expiredTimeMillis, CpuHeadroomParamsInternal params, + float[] headroom, long pid) { + mExpiredTimeMillis = expiredTimeMillis; + mParams = params; + mPid = pid; + mHeadroom = headroom; + } + + private boolean match(CpuHeadroomParamsInternal params, long pid) { + if (mParams == null && params == null) return true; + if (mParams != null) { + return mParams.equals(params) && pid == mPid; + } + return false; + } + + private boolean isExpired() { + return System.currentTimeMillis() > mExpiredTimeMillis; + } + } + + @GuardedBy("mCpuHeadroomLock") + private final List<CpuHeadroomCacheItem> mCpuHeadroomCache; + private final long mCpuHeadroomIntervalMillis; + + private final Object mGpuHeadroomLock = new Object(); + + private static class GpuHeadroomCacheItem { + long mExpiredTimeMillis; + GpuHeadroomParamsInternal mParams; + float mHeadroom; + + GpuHeadroomCacheItem(long expiredTimeMillis, GpuHeadroomParamsInternal params, + float headroom) { + mExpiredTimeMillis = expiredTimeMillis; + mParams = params; + mHeadroom = headroom; + } + + private boolean match(GpuHeadroomParamsInternal params) { + if (mParams == null && params == null) return true; + if (mParams != null) { + return mParams.equals(params); + } + return false; + } + + private boolean isExpired() { + return System.currentTimeMillis() > mExpiredTimeMillis; + } + } + + @GuardedBy("mGpuHeadroomLock") + private final List<GpuHeadroomCacheItem> mGpuHeadroomCache; + private final long mGpuHeadroomIntervalMillis; + + @VisibleForTesting + final IHintManager.Stub mService = new BinderService(); public HintManagerService(Context context) { this(context, new Injector()); @@ -197,13 +271,72 @@ public final class HintManagerService extends SystemService { mPowerHal = injector.createIPower(); mPowerHalVersion = 0; mUsesFmq = false; + long cpuHeadroomIntervalMillis = HEADROOM_INTERVAL_UNSUPPORTED; + long gpuHeadroomIntervalMillis = HEADROOM_INTERVAL_UNSUPPORTED; if (mPowerHal != null) { try { mPowerHalVersion = mPowerHal.getInterfaceVersion(); + if (mPowerHal.getInterfaceVersion() >= 6) { + if (SystemProperties.getBoolean(PROPERTY_USE_HAL_HEADROOMS, true)) { + cpuHeadroomIntervalMillis = checkCpuHeadroomSupport(); + gpuHeadroomIntervalMillis = checkGpuHeadroomSupport(); + } + } } catch (RemoteException e) { throw new IllegalStateException("Could not contact PowerHAL!", e); } } + mCpuHeadroomIntervalMillis = cpuHeadroomIntervalMillis; + mGpuHeadroomIntervalMillis = gpuHeadroomIntervalMillis; + if (mCpuHeadroomIntervalMillis > 0) { + mCpuHeadroomCache = new ArrayList<>(4); + } else { + mCpuHeadroomCache = null; + } + if (mGpuHeadroomIntervalMillis > 0) { + mGpuHeadroomCache = new ArrayList<>(2); + } else { + mGpuHeadroomCache = null; + } + } + + private long checkCpuHeadroomSupport() { + try { + synchronized (mCpuHeadroomLock) { + final CpuHeadroomParams defaultParams = new CpuHeadroomParams(); + defaultParams.pid = Process.myPid(); + float[] ret = mPowerHal.getCpuHeadroom(defaultParams); + if (ret != null && ret.length > 0) { + return Math.max( + DEFAULT_CPU_HEADROOM_INTERVAL_MILLIS, + mPowerHal.getCpuHeadroomMinIntervalMillis()); + } + } + + } catch (UnsupportedOperationException e) { + Slog.w(TAG, "getCpuHeadroom HAL API is not supported", e); + } catch (RemoteException e) { + Slog.e(TAG, "getCpuHeadroom HAL API fails, disabling the API", e); + } + return HEADROOM_INTERVAL_UNSUPPORTED; + } + + private long checkGpuHeadroomSupport() { + try { + synchronized (mGpuHeadroomLock) { + float ret = mPowerHal.getGpuHeadroom(new GpuHeadroomParams()); + if (!Float.isNaN(ret)) { + return Math.max( + DEFAULT_GPU_HEADROOM_INTERVAL_MILLIS, + mPowerHal.getGpuHeadroomMinIntervalMillis()); + } + } + } catch (UnsupportedOperationException e) { + Slog.w(TAG, "getGpuHeadroom HAL API is not supported", e); + } catch (RemoteException e) { + Slog.e(TAG, "getGpuHeadroom HAL API fails, disabling the API", e); + } + return HEADROOM_INTERVAL_UNSUPPORTED; } private ServiceThread createCleanUpThread() { @@ -738,7 +871,7 @@ public final class HintManagerService extends SystemService { mLinked = false; } if (mConfig != null) { - try { + try { mPowerHal.closeSessionChannel(mTgid, mUid); } catch (RemoteException e) { throw new IllegalStateException("Failed to close session channel!", e); @@ -982,13 +1115,13 @@ public final class HintManagerService extends SystemService { } // returns the first invalid tid or null if not found - private Integer checkTidValid(int uid, int tgid, int [] tids, IntArray nonIsolated) { + private Integer checkTidValid(int uid, int tgid, int[] tids, IntArray nonIsolated) { // Make sure all tids belongs to the same UID (including isolated UID), // tids can belong to different application processes. List<Integer> isolatedPids = null; for (int i = 0; i < tids.length; i++) { int tid = tids[i]; - final String[] procStatusKeys = new String[] { + final String[] procStatusKeys = new String[]{ "Uid:", "Tgid:" }; @@ -1058,7 +1191,7 @@ public final class HintManagerService extends SystemService { Slogf.w(TAG, errMsg); throw new SecurityException(errMsg); } - if (resetOnForkEnabled()){ + if (resetOnForkEnabled()) { try { for (int tid : tids) { int policy = Process.getThreadScheduler(tid); @@ -1214,6 +1347,124 @@ public final class HintManagerService extends SystemService { } @Override + public float[] getCpuHeadroom(@Nullable CpuHeadroomParamsInternal params) { + if (mCpuHeadroomIntervalMillis <= 0) { + throw new UnsupportedOperationException(); + } + CpuHeadroomParams halParams = new CpuHeadroomParams(); + halParams.pid = Binder.getCallingPid(); + if (params != null) { + halParams.calculationType = params.calculationType; + halParams.selectionType = params.selectionType; + if (params.usesDeviceHeadroom) { + halParams.pid = DEFAULT_HEADROOM_PID; + } + } + synchronized (mCpuHeadroomLock) { + while (!mCpuHeadroomCache.isEmpty()) { + if (mCpuHeadroomCache.getFirst().isExpired()) { + mCpuHeadroomCache.removeFirst(); + } else { + break; + } + } + for (int i = 0; i < mCpuHeadroomCache.size(); ++i) { + final CpuHeadroomCacheItem item = mCpuHeadroomCache.get(i); + if (item.match(params, halParams.pid)) { + item.mExpiredTimeMillis = + System.currentTimeMillis() + mCpuHeadroomIntervalMillis; + mCpuHeadroomCache.remove(i); + mCpuHeadroomCache.add(item); + return item.mHeadroom; + } + } + } + // return from HAL directly + try { + float[] headroom = mPowerHal.getCpuHeadroom(halParams); + if (headroom == null || headroom.length == 0) { + Slog.wtf(TAG, + "CPU headroom from Power HAL is invalid: " + Arrays.toString(headroom)); + return new float[]{Float.NaN}; + } + synchronized (mCpuHeadroomLock) { + mCpuHeadroomCache.add(new CpuHeadroomCacheItem( + System.currentTimeMillis() + mCpuHeadroomIntervalMillis, + params, headroom, halParams.pid + )); + } + return headroom; + + } catch (RemoteException e) { + return new float[]{Float.NaN}; + } + } + + @Override + public float getGpuHeadroom(@Nullable GpuHeadroomParamsInternal params) { + if (mGpuHeadroomIntervalMillis <= 0) { + throw new UnsupportedOperationException(); + } + GpuHeadroomParams halParams = new GpuHeadroomParams(); + if (params != null) { + halParams.calculationType = params.calculationType; + } + synchronized (mGpuHeadroomLock) { + while (!mGpuHeadroomCache.isEmpty()) { + if (mGpuHeadroomCache.getFirst().isExpired()) { + mGpuHeadroomCache.removeFirst(); + } else { + break; + } + } + for (int i = 0; i < mGpuHeadroomCache.size(); ++i) { + final GpuHeadroomCacheItem item = mGpuHeadroomCache.get(i); + if (item.match(params)) { + item.mExpiredTimeMillis = + System.currentTimeMillis() + mGpuHeadroomIntervalMillis; + mGpuHeadroomCache.remove(i); + mGpuHeadroomCache.add(item); + return item.mHeadroom; + } + } + } + // return from HAL directly + try { + float headroom = mPowerHal.getGpuHeadroom(halParams); + if (Float.isNaN(headroom)) { + Slog.wtf(TAG, + "GPU headroom from Power HAL is NaN"); + return Float.NaN; + } + synchronized (mGpuHeadroomLock) { + mGpuHeadroomCache.add(new GpuHeadroomCacheItem( + System.currentTimeMillis() + mGpuHeadroomIntervalMillis, + params, headroom + )); + } + return headroom; + } catch (RemoteException e) { + return Float.NaN; + } + } + + @Override + public long getCpuHeadroomMinIntervalMillis() throws RemoteException { + if (mCpuHeadroomIntervalMillis <= 0) { + throw new UnsupportedOperationException(); + } + return mCpuHeadroomIntervalMillis; + } + + @Override + public long getGpuHeadroomMinIntervalMillis() throws RemoteException { + if (mGpuHeadroomIntervalMillis <= 0) { + throw new UnsupportedOperationException(); + } + return mGpuHeadroomIntervalMillis; + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { return; @@ -1235,6 +1486,25 @@ public final class HintManagerService extends SystemService { } } } + pw.println("CPU Headroom Interval: " + mCpuHeadroomIntervalMillis); + pw.println("GPU Headroom Interval: " + mGpuHeadroomIntervalMillis); + try { + CpuHeadroomParamsInternal params = new CpuHeadroomParamsInternal(); + params.selectionType = CpuHeadroomParams.SelectionType.ALL; + params.usesDeviceHeadroom = true; + pw.println("CPU headroom: " + Arrays.toString(getCpuHeadroom(params))); + params = new CpuHeadroomParamsInternal(); + params.selectionType = CpuHeadroomParams.SelectionType.PER_CORE; + params.usesDeviceHeadroom = true; + pw.println("CPU headroom per core: " + Arrays.toString(getCpuHeadroom(params))); + } catch (Exception e) { + pw.println("CPU headroom: N/A"); + } + try { + pw.println("GPU headroom: " + getGpuHeadroom(null)); + } catch (Exception e) { + pw.println("GPU headroom: N/A"); + } } private void logPerformanceHintSessionAtom(int uid, long sessionId, @@ -1467,7 +1737,7 @@ public final class HintManagerService extends SystemService { Slogf.w(TAG, errMsg); throw new SecurityException(errMsg); } - if (resetOnForkEnabled()){ + if (resetOnForkEnabled()) { try { for (int tid : tids) { int policy = Process.getThreadScheduler(tid); diff --git a/services/core/java/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationService.java b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java index b129fdc1b6e3..b8a4a9c26feb 100644 --- a/services/core/java/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationService.java +++ b/services/core/java/com/android/server/security/authenticationpolicy/AuthenticationPolicyService.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.security.adaptiveauthentication; +package com.android.server.security.authenticationpolicy; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST; @@ -55,8 +55,8 @@ import java.util.Objects; /** * @hide */ -public class AdaptiveAuthenticationService extends SystemService { - private static final String TAG = "AdaptiveAuthenticationService"; +public class AuthenticationPolicyService extends SystemService { + private static final String TAG = "AuthenticationPolicyService"; private static final boolean DEBUG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.DEBUG); @VisibleForTesting @@ -78,12 +78,12 @@ public class AdaptiveAuthenticationService extends SystemService { final SparseIntArray mFailedAttemptsForUser = new SparseIntArray(); private final SparseLongArray mLastLockedTimestamp = new SparseLongArray(); - public AdaptiveAuthenticationService(Context context) { + public AuthenticationPolicyService(Context context) { this(context, new LockPatternUtils(context)); } @VisibleForTesting - public AdaptiveAuthenticationService(Context context, LockPatternUtils lockPatternUtils) { + public AuthenticationPolicyService(Context context, LockPatternUtils lockPatternUtils) { super(context); mLockPatternUtils = lockPatternUtils; mLockSettings = Objects.requireNonNull( diff --git a/services/core/java/com/android/server/security/adaptiveauthentication/OWNERS b/services/core/java/com/android/server/security/authenticationpolicy/OWNERS index 29affcdb81aa..29affcdb81aa 100644 --- a/services/core/java/com/android/server/security/adaptiveauthentication/OWNERS +++ b/services/core/java/com/android/server/security/authenticationpolicy/OWNERS diff --git a/services/core/java/com/android/server/security/forensic/BackupTransportConnection.java b/services/core/java/com/android/server/security/forensic/ForensicEventTransportConnection.java index caca011b6549..b85199ed9218 100644 --- a/services/core/java/com/android/server/security/forensic/BackupTransportConnection.java +++ b/services/core/java/com/android/server/security/forensic/ForensicEventTransportConnection.java @@ -16,15 +16,19 @@ package com.android.server.security.forensic; +import static android.Manifest.permission.BIND_FORENSIC_EVENT_TRANSPORT_SERVICE; + import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; import android.security.forensic.ForensicEvent; -import android.security.forensic.IBackupTransport; +import android.security.forensic.IForensicEventTransport; import android.text.TextUtils; import android.util.Slog; @@ -36,20 +40,20 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -public class BackupTransportConnection implements ServiceConnection { - private static final String TAG = "BackupTransportConnection"; +public class ForensicEventTransportConnection implements ServiceConnection { + private static final String TAG = "ForensicEventTransportConnection"; private static final long FUTURE_TIMEOUT_MILLIS = 60 * 1000; // 1 mins private final Context mContext; - private String mForensicBackupTransportConfig; - volatile IBackupTransport mService; + private String mForensicEventTransportConfig; + volatile IForensicEventTransport mService; - public BackupTransportConnection(Context context) { + public ForensicEventTransportConnection(Context context) { mContext = context; mService = null; } /** - * Initialize the BackupTransport binder service. + * Initialize the ForensicEventTransport binder service. * @return Whether the initialization succeed. */ public boolean initialize() { @@ -74,7 +78,7 @@ public class BackupTransportConnection implements ServiceConnection { } /** - * Add data to the BackupTransport binder service. + * Add data to the ForensicEventTransport binder service. * @param data List of ForensicEvent. * @return Whether the data is added to the binder service. */ @@ -109,21 +113,37 @@ public class BackupTransportConnection implements ServiceConnection { return future.get(FUTURE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException | TimeoutException | CancellationException e) { - Slog.w(TAG, "Failed to get result from transport:", e); + Slog.e(TAG, "Failed to get result from transport:", e); return null; } } private boolean bindService() { - mForensicBackupTransportConfig = mContext.getString( - com.android.internal.R.string.config_forensicBackupTransport); - if (TextUtils.isEmpty(mForensicBackupTransportConfig)) { + mForensicEventTransportConfig = mContext.getString( + com.android.internal.R.string.config_forensicEventTransport); + if (TextUtils.isEmpty(mForensicEventTransportConfig)) { + Slog.e(TAG, "config_forensicEventTransport is empty"); return false; } ComponentName serviceComponent = - ComponentName.unflattenFromString(mForensicBackupTransportConfig); + ComponentName.unflattenFromString(mForensicEventTransportConfig); if (serviceComponent == null) { + Slog.e(TAG, "Can't get serviceComponent name"); + return false; + } + + try { + ServiceInfo serviceInfo = mContext.getPackageManager().getServiceInfo(serviceComponent, + 0 /* flags */); + if (!BIND_FORENSIC_EVENT_TRANSPORT_SERVICE.equals(serviceInfo.permission)) { + Slog.e(TAG, serviceComponent.flattenToShortString() + + " is not declared with the permission " + + "\"" + BIND_FORENSIC_EVENT_TRANSPORT_SERVICE + "\""); + return false; + } + } catch (PackageManager.NameNotFoundException e) { + Slog.e(TAG, "Unable to find serviceComponent"); return false; } @@ -143,7 +163,7 @@ public class BackupTransportConnection implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { - mService = IBackupTransport.Stub.asInterface(service); + mService = IForensicEventTransport.Stub.asInterface(service); } @Override diff --git a/services/core/java/com/android/server/security/forensic/ForensicService.java b/services/core/java/com/android/server/security/forensic/ForensicService.java index 01f630b60ff5..2be068fa2f83 100644 --- a/services/core/java/com/android/server/security/forensic/ForensicService.java +++ b/services/core/java/com/android/server/security/forensic/ForensicService.java @@ -16,11 +16,16 @@ package com.android.server.security.forensic; +import static android.Manifest.permission.MANAGE_FORENSIC_STATE; +import static android.Manifest.permission.READ_FORENSIC_STATE; + +import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.PermissionEnforcer; import android.os.RemoteException; import android.security.forensic.ForensicEvent; import android.security.forensic.IForensicService; @@ -41,16 +46,15 @@ import java.util.List; public class ForensicService extends SystemService { private static final String TAG = "ForensicService"; - private static final int MSG_MONITOR_STATE = 0; - private static final int MSG_MAKE_VISIBLE = 1; - private static final int MSG_MAKE_INVISIBLE = 2; - private static final int MSG_ENABLE = 3; - private static final int MSG_DISABLE = 4; - private static final int MSG_BACKUP = 5; + private static final int MAX_STATE_CALLBACK_NUM = 16; + private static final int MSG_ADD_STATE_CALLBACK = 0; + private static final int MSG_REMOVE_STATE_CALLBACK = 1; + private static final int MSG_ENABLE = 2; + private static final int MSG_DISABLE = 3; + private static final int MSG_TRANSPORT = 4; private static final int STATE_UNKNOWN = IForensicServiceStateCallback.State.UNKNOWN; - private static final int STATE_INVISIBLE = IForensicServiceStateCallback.State.INVISIBLE; - private static final int STATE_VISIBLE = IForensicServiceStateCallback.State.VISIBLE; + private static final int STATE_DISABLED = IForensicServiceStateCallback.State.DISABLED; private static final int STATE_ENABLED = IForensicServiceStateCallback.State.ENABLED; private static final int ERROR_UNKNOWN = IForensicServiceCommandCallback.ErrorCode.UNKNOWN; @@ -58,19 +62,19 @@ public class ForensicService extends SystemService { IForensicServiceCommandCallback.ErrorCode.PERMISSION_DENIED; private static final int ERROR_INVALID_STATE_TRANSITION = IForensicServiceCommandCallback.ErrorCode.INVALID_STATE_TRANSITION; - private static final int ERROR_BACKUP_TRANSPORT_UNAVAILABLE = - IForensicServiceCommandCallback.ErrorCode.BACKUP_TRANSPORT_UNAVAILABLE; + private static final int ERROR_TRANSPORT_UNAVAILABLE = + IForensicServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE; private static final int ERROR_DATA_SOURCE_UNAVAILABLE = IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE; private final Context mContext; private final Handler mHandler; - private final BackupTransportConnection mBackupTransportConnection; + private final ForensicEventTransportConnection mForensicEventTransportConnection; private final DataAggregator mDataAggregator; private final BinderService mBinderService; - private final ArrayList<IForensicServiceStateCallback> mStateMonitors = new ArrayList<>(); - private volatile int mState = STATE_INVISIBLE; + private final ArrayList<IForensicServiceStateCallback> mStateCallbacks = new ArrayList<>(); + private volatile int mState = STATE_DISABLED; public ForensicService(@NonNull Context context) { this(new InjectorImpl(context)); @@ -81,9 +85,9 @@ public class ForensicService extends SystemService { super(injector.getContext()); mContext = injector.getContext(); mHandler = new EventHandler(injector.getLooper(), this); - mBackupTransportConnection = injector.getBackupTransportConnection(); + mForensicEventTransportConnection = injector.getForensicEventransportConnection(); mDataAggregator = injector.getDataAggregator(this); - mBinderService = new BinderService(this); + mBinderService = new BinderService(this, injector.getPermissionEnforcer()); } @VisibleForTesting @@ -94,32 +98,36 @@ public class ForensicService extends SystemService { private static final class BinderService extends IForensicService.Stub { final ForensicService mService; - BinderService(ForensicService service) { + BinderService(ForensicService service, @NonNull PermissionEnforcer permissionEnforcer) { + super(permissionEnforcer); mService = service; } @Override - public void monitorState(IForensicServiceStateCallback callback) { - mService.mHandler.obtainMessage(MSG_MONITOR_STATE, callback).sendToTarget(); - } - - @Override - public void makeVisible(IForensicServiceCommandCallback callback) { - mService.mHandler.obtainMessage(MSG_MAKE_VISIBLE, callback).sendToTarget(); + @EnforcePermission(READ_FORENSIC_STATE) + public void addStateCallback(IForensicServiceStateCallback callback) { + addStateCallback_enforcePermission(); + mService.mHandler.obtainMessage(MSG_ADD_STATE_CALLBACK, callback).sendToTarget(); } @Override - public void makeInvisible(IForensicServiceCommandCallback callback) { - mService.mHandler.obtainMessage(MSG_MAKE_INVISIBLE, callback).sendToTarget(); + @EnforcePermission(READ_FORENSIC_STATE) + public void removeStateCallback(IForensicServiceStateCallback callback) { + removeStateCallback_enforcePermission(); + mService.mHandler.obtainMessage(MSG_REMOVE_STATE_CALLBACK, callback).sendToTarget(); } @Override + @EnforcePermission(MANAGE_FORENSIC_STATE) public void enable(IForensicServiceCommandCallback callback) { + enable_enforcePermission(); mService.mHandler.obtainMessage(MSG_ENABLE, callback).sendToTarget(); } @Override + @EnforcePermission(MANAGE_FORENSIC_STATE) public void disable(IForensicServiceCommandCallback callback) { + disable_enforcePermission(); mService.mHandler.obtainMessage(MSG_DISABLE, callback).sendToTarget(); } } @@ -135,24 +143,18 @@ public class ForensicService extends SystemService { @Override public void handleMessage(Message msg) { switch (msg.what) { - case MSG_MONITOR_STATE: + case MSG_ADD_STATE_CALLBACK: try { - mService.monitorState( + mService.addStateCallback( (IForensicServiceStateCallback) msg.obj); } catch (RemoteException e) { Slog.e(TAG, "RemoteException", e); } break; - case MSG_MAKE_VISIBLE: + case MSG_REMOVE_STATE_CALLBACK: try { - mService.makeVisible((IForensicServiceCommandCallback) msg.obj); - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException", e); - } - break; - case MSG_MAKE_INVISIBLE: - try { - mService.makeInvisible((IForensicServiceCommandCallback) msg.obj); + mService.removeStateCallback( + (IForensicServiceStateCallback) msg.obj); } catch (RemoteException e) { Slog.e(TAG, "RemoteException", e); } @@ -171,8 +173,8 @@ public class ForensicService extends SystemService { Slog.e(TAG, "RemoteException", e); } break; - case MSG_BACKUP: - mService.backup((List<ForensicEvent>) msg.obj); + case MSG_TRANSPORT: + mService.transport((List<ForensicEvent>) msg.obj); break; default: Slog.w(TAG, "Unknown message: " + msg.what); @@ -180,103 +182,83 @@ public class ForensicService extends SystemService { } } - private void monitorState(IForensicServiceStateCallback callback) throws RemoteException { - for (int i = 0; i < mStateMonitors.size(); i++) { - if (mStateMonitors.get(i).asBinder() == callback.asBinder()) { + private void addStateCallback(IForensicServiceStateCallback callback) throws RemoteException { + for (int i = 0; i < mStateCallbacks.size(); i++) { + if (mStateCallbacks.get(i).asBinder() == callback.asBinder()) { return; } } - mStateMonitors.add(callback); + mStateCallbacks.add(callback); callback.onStateChange(mState); } - private void notifyStateMonitors() throws RemoteException { - for (int i = 0; i < mStateMonitors.size(); i++) { - mStateMonitors.get(i).onStateChange(mState); + private void removeStateCallback(IForensicServiceStateCallback callback) + throws RemoteException { + for (int i = 0; i < mStateCallbacks.size(); i++) { + if (mStateCallbacks.get(i).asBinder() == callback.asBinder()) { + mStateCallbacks.remove(i); + return; + } } } - private void makeVisible(IForensicServiceCommandCallback callback) throws RemoteException { - switch (mState) { - case STATE_INVISIBLE: - if (!mDataAggregator.initialize()) { - callback.onFailure(ERROR_DATA_SOURCE_UNAVAILABLE); - break; - } - mState = STATE_VISIBLE; - notifyStateMonitors(); - callback.onSuccess(); - break; - case STATE_VISIBLE: - callback.onSuccess(); - break; - default: - callback.onFailure(ERROR_INVALID_STATE_TRANSITION); + private void notifyStateMonitors() { + if (mStateCallbacks.size() >= MAX_STATE_CALLBACK_NUM) { + mStateCallbacks.removeFirst(); } - } - private void makeInvisible(IForensicServiceCommandCallback callback) throws RemoteException { - switch (mState) { - case STATE_VISIBLE: - case STATE_ENABLED: - mState = STATE_INVISIBLE; - notifyStateMonitors(); - callback.onSuccess(); - break; - case STATE_INVISIBLE: - callback.onSuccess(); - break; - default: - callback.onFailure(ERROR_INVALID_STATE_TRANSITION); + for (int i = 0; i < mStateCallbacks.size(); i++) { + try { + mStateCallbacks.get(i).onStateChange(mState); + } catch (RemoteException e) { + mStateCallbacks.remove(i); + } } } private void enable(IForensicServiceCommandCallback callback) throws RemoteException { - switch (mState) { - case STATE_VISIBLE: - if (!mBackupTransportConnection.initialize()) { - callback.onFailure(ERROR_BACKUP_TRANSPORT_UNAVAILABLE); - break; - } - mDataAggregator.enable(); - mState = STATE_ENABLED; - notifyStateMonitors(); - callback.onSuccess(); - break; - case STATE_ENABLED: - callback.onSuccess(); - break; - default: - callback.onFailure(ERROR_INVALID_STATE_TRANSITION); + if (mState == STATE_ENABLED) { + callback.onSuccess(); + return; } + + // TODO: temporarily disable the following for the CTS ForensicManagerTest. + // Enable it when the transport component is ready. + // if (!mForensicEventTransportConnection.initialize()) { + // callback.onFailure(ERROR_TRANSPORT_UNAVAILABLE); + // return; + // } + + mDataAggregator.enable(); + mState = STATE_ENABLED; + notifyStateMonitors(); + callback.onSuccess(); } private void disable(IForensicServiceCommandCallback callback) throws RemoteException { - switch (mState) { - case STATE_ENABLED: - mBackupTransportConnection.release(); - mDataAggregator.disable(); - mState = STATE_VISIBLE; - notifyStateMonitors(); - callback.onSuccess(); - break; - case STATE_VISIBLE: - callback.onSuccess(); - break; - default: - callback.onFailure(ERROR_INVALID_STATE_TRANSITION); + if (mState == STATE_DISABLED) { + callback.onSuccess(); + return; } + + // TODO: temporarily disable the following for the CTS ForensicManagerTest. + // Enable it when the transport component is ready. + // mForensicEventTransportConnection.release(); + mDataAggregator.disable(); + mState = STATE_DISABLED; + notifyStateMonitors(); + callback.onSuccess(); } /** * Add a list of ForensicEvent. */ public void addNewData(List<ForensicEvent> events) { - mHandler.obtainMessage(MSG_BACKUP, events).sendToTarget(); + mHandler.obtainMessage(MSG_TRANSPORT, events).sendToTarget(); } - private void backup(List<ForensicEvent> events) { - mBackupTransportConnection.addData(events); + private void transport(List<ForensicEvent> events) { + mForensicEventTransportConnection.addData(events); } @Override @@ -296,9 +278,11 @@ public class ForensicService extends SystemService { interface Injector { Context getContext(); + PermissionEnforcer getPermissionEnforcer(); + Looper getLooper(); - BackupTransportConnection getBackupTransportConnection(); + ForensicEventTransportConnection getForensicEventransportConnection(); DataAggregator getDataAggregator(ForensicService forensicService); } @@ -315,6 +299,10 @@ public class ForensicService extends SystemService { return mContext; } + @Override + public PermissionEnforcer getPermissionEnforcer() { + return PermissionEnforcer.fromContext(mContext); + } @Override public Looper getLooper() { @@ -326,8 +314,8 @@ public class ForensicService extends SystemService { } @Override - public BackupTransportConnection getBackupTransportConnection() { - return new BackupTransportConnection(mContext); + public ForensicEventTransportConnection getForensicEventransportConnection() { + return new ForensicEventTransportConnection(mContext); } @Override diff --git a/services/core/java/com/android/server/security/forensic/SecurityLogSource.java b/services/core/java/com/android/server/security/forensic/SecurityLogSource.java index 0f1aa42a2f46..e1b49c42018b 100644 --- a/services/core/java/com/android/server/security/forensic/SecurityLogSource.java +++ b/services/core/java/com/android/server/security/forensic/SecurityLogSource.java @@ -22,9 +22,7 @@ import android.app.admin.DevicePolicyManager; import android.app.admin.SecurityLog.SecurityEvent; import android.content.Context; import android.security.forensic.ForensicEvent; -import android.util.ArrayMap; -import java.util.Arrays; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -34,10 +32,6 @@ import java.util.stream.Collectors; public class SecurityLogSource implements DataSource { private static final String TAG = "Forensic SecurityLogSource"; - private static final String EVENT_TYPE = "SecurityEvent"; - private static final String EVENT_TAG = "TAG"; - private static final String EVENT_TIME = "TIME"; - private static final String EVENT_DATA = "DATA"; private SecurityEventCallback mEventCallback = new SecurityEventCallback(); private DevicePolicyManager mDpm; @@ -94,46 +88,9 @@ public class SecurityLogSource implements DataSource { List<ForensicEvent> forensicEvents = events.stream() .filter(event -> event != null) - .map(event -> toForensicEvent(event)) + .map(event -> new ForensicEvent(event)) .collect(Collectors.toList()); mDataAggregator.addBatchData(forensicEvents); } - - private ForensicEvent toForensicEvent(SecurityEvent event) { - ArrayMap<String, String> keyValuePairs = new ArrayMap<>(); - keyValuePairs.put(EVENT_TIME, String.valueOf(event.getTimeNanos())); - // TODO: Map tag to corresponding string - keyValuePairs.put(EVENT_TAG, String.valueOf(event.getTag())); - keyValuePairs.put(EVENT_DATA, eventDataToString(event.getData())); - return new ForensicEvent(EVENT_TYPE, keyValuePairs); - } - - /** - * Convert event data to a String. - * - * @param obj Object containing an Integer, Long, Float, String, null, or Object[] of the - * same. - * @return String representation of event data. - */ - private String eventDataToString(Object obj) { - if (obj == null) { - return ""; - } else if (obj instanceof Integer - || obj instanceof Long - || obj instanceof Float - || obj instanceof String) { - return String.valueOf(obj); - } else if (obj instanceof Object[]) { - Object[] objArray = (Object[]) obj; - String[] strArray = new String[objArray.length]; - for (int i = 0; i < objArray.length; ++i) { - strArray[i] = eventDataToString(objArray[i]); - } - return Arrays.toString((String[]) strArray); - } else { - throw new IllegalArgumentException( - "Unsupported data type: " + obj.getClass().getSimpleName()); - } - } } } diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 465ac2f1731d..887e1861f789 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -61,6 +61,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -84,6 +85,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; import com.android.internal.infra.AndroidFuture; +import com.android.internal.policy.IDeviceLockedStateListener; import com.android.internal.util.DumpUtils; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockSettingsInternal; @@ -105,6 +107,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.stream.IntStream; /** * Manages trust agents and trust listeners. @@ -253,6 +256,10 @@ public class TrustManagerService extends SystemService { new SparseArray<>(); private final SparseArray<TrustableTimeoutAlarmListener> mIdleTrustableTimeoutAlarmListenerForUser = new SparseArray<>(); + + private final RemoteCallbackList<IDeviceLockedStateListener> + mDeviceLockedStateListeners = new RemoteCallbackList<>(); + private AlarmManager mAlarmManager; private final Object mAlarmLock = new Object(); @@ -1090,6 +1097,7 @@ public class TrustManagerService extends SystemService { if (changed) { notifyTrustAgentsOfDeviceLockState(userId, locked); notifyKeystoreOfDeviceLockState(userId, locked); + notifyDeviceLockedListenersForUser(userId, locked); // Also update the user's profiles who have unified challenge, since they // share the same unlocked state (see {@link #isDeviceLocked(int)}) for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) { @@ -1910,6 +1918,26 @@ public class TrustManagerService extends SystemService { return mIsInSignificantPlace; } + @EnforcePermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) + @Override + public void registerDeviceLockedStateListener(IDeviceLockedStateListener listener, + int deviceId) { + super.registerDeviceLockedStateListener_enforcePermission(); + if (deviceId != Context.DEVICE_ID_DEFAULT) { + // Virtual devices are considered insecure. + return; + } + mDeviceLockedStateListeners.register(listener, + Integer.valueOf(UserHandle.getUserId(Binder.getCallingUid()))); + } + + @EnforcePermission(Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) + @Override + public void unregisterDeviceLockedStateListener(IDeviceLockedStateListener listener) { + super.unregisterDeviceLockedStateListener_enforcePermission(); + mDeviceLockedStateListeners.unregister(listener); + } + private void enforceReportPermission() { mContext.enforceCallingOrSelfPermission( Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events"); @@ -2031,6 +2059,7 @@ public class TrustManagerService extends SystemService { } notifyKeystoreOfDeviceLockState(userId, locked); + notifyDeviceLockedListenersForUser(userId, locked); if (locked) { try { @@ -2497,4 +2526,24 @@ public class TrustManagerService extends SystemService { updateTrust(mUserId, 0 /* flags */); } } + + private void notifyDeviceLockedListenersForUser(int userId, boolean locked) { + int numListeners = mDeviceLockedStateListeners.beginBroadcast(); + try { + IntStream.range(0, numListeners).forEach(i -> { + try { + Integer uid = (Integer) mDeviceLockedStateListeners.getBroadcastCookie(i); + if (userId == uid.intValue()) { + mDeviceLockedStateListeners.getBroadcastItem(i) + .onDeviceLockedStateChanged(locked); + } + } catch (RemoteException re) { + Log.i(TAG, "Service died", re); + } + }); + + } finally { + mDeviceLockedStateListeners.finishBroadcast(); + } + } } diff --git a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java index 07478e360d27..9e75cf2fc3f3 100644 --- a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java +++ b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java @@ -37,8 +37,11 @@ import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; @@ -60,6 +63,9 @@ final class VendorVibrationSession extends IVibrationSession.Stub * used for another vibration. */ void onSessionReleased(long sessionId); + + /** Request the manager to trigger a vibration within this session. */ + void vibrate(long sessionId, CallerInfo callerInfo, CombinedVibration vibration); } private final Object mLock = new Object(); @@ -71,7 +77,9 @@ final class VendorVibrationSession extends IVibrationSession.Stub private final IVibrationSessionCallback mCallback; private final CallerInfo mCallerInfo; private final VibratorManagerHooks mManagerHooks; + private final DeviceAdapter mDeviceAdapter; private final Handler mHandler; + private final List<DebugInfo> mVibrations = new ArrayList<>(); @GuardedBy("mLock") private Status mStatus = Status.RUNNING; @@ -83,24 +91,28 @@ final class VendorVibrationSession extends IVibrationSession.Stub private long mEndUptime; @GuardedBy("mLock") private long mEndTime; // for debugging + @GuardedBy("mLock") + private VibrationStepConductor mConductor; VendorVibrationSession(@NonNull CallerInfo callerInfo, @NonNull Handler handler, - @NonNull VibratorManagerHooks managerHooks, @NonNull int[] vibratorIds, + @NonNull VibratorManagerHooks managerHooks, @NonNull DeviceAdapter deviceAdapter, @NonNull IVibrationSessionCallback callback) { mCreateUptime = SystemClock.uptimeMillis(); mCreateTime = System.currentTimeMillis(); - mVibratorIds = vibratorIds; + mVibratorIds = deviceAdapter.getAvailableVibratorIds(); mHandler = handler; mCallback = callback; mCallerInfo = callerInfo; mManagerHooks = managerHooks; + mDeviceAdapter = deviceAdapter; CancellationSignal.fromTransport(mCancellationSignal).setOnCancelListener(this); } @Override public void vibrate(CombinedVibration vibration, String reason) { - // TODO(b/345414356): implement vibration support - throw new UnsupportedOperationException("Vendor session vibrations not yet implemented"); + CallerInfo vibrationCallerInfo = new CallerInfo(mCallerInfo.attrs, mCallerInfo.uid, + mCallerInfo.deviceId, mCallerInfo.opPkg, reason); + mManagerHooks.vibrate(mSessionId, vibrationCallerInfo, vibration); } @Override @@ -146,7 +158,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub public DebugInfo getDebugInfo() { synchronized (mLock) { return new DebugInfoImpl(mStatus, mCallerInfo, mCreateUptime, mCreateTime, mStartTime, - mEndUptime, mEndTime); + mEndUptime, mEndTime, mVibrations); } } @@ -200,12 +212,12 @@ final class VendorVibrationSession extends IVibrationSession.Stub @Override public void notifyVibratorCallback(int vibratorId, long vibrationId) { - // TODO(b/345414356): implement vibration support + // Ignore it, the session vibration playback doesn't depend on HAL timings } @Override public void notifySyncedVibratorsCallback(long vibrationId) { - // TODO(b/345414356): implement vibration support + // Ignore it, the session vibration playback doesn't depend on HAL timings } @Override @@ -214,8 +226,9 @@ final class VendorVibrationSession extends IVibrationSession.Stub // If end was not requested then the HAL has cancelled the session. maybeSetEndRequestLocked(Status.CANCELLED_BY_UNKNOWN_REASON); maybeSetStatusToRequestedLocked(); + clearVibrationConductor(); } - mManagerHooks.onSessionReleased(mSessionId); + mHandler.post(() -> mManagerHooks.onSessionReleased(mSessionId)); } @Override @@ -228,7 +241,8 @@ final class VendorVibrationSession extends IVibrationSession.Stub /* includeDate= */ true)) + ", status: " + mStatus.name().toLowerCase(Locale.ROOT) + ", callerInfo: " + mCallerInfo - + ", vibratorIds: " + Arrays.toString(mVibratorIds); + + ", vibratorIds: " + Arrays.toString(mVibratorIds) + + ", vibrations: " + mVibrations; } } @@ -254,6 +268,13 @@ final class VendorVibrationSession extends IVibrationSession.Stub return mVibratorIds; } + @VisibleForTesting + public List<DebugInfo> getVibrations() { + synchronized (mLock) { + return new ArrayList<>(mVibrations); + } + } + public ICancellationSignal getCancellationSignal() { return mCancellationSignal; } @@ -278,7 +299,39 @@ final class VendorVibrationSession extends IVibrationSession.Stub } if (isAlreadyEnded) { // Session already ended, make sure we end it in the HAL. - mManagerHooks.endSession(mSessionId, /* shouldAbort= */ true); + mHandler.post(() -> mManagerHooks.endSession(mSessionId, /* shouldAbort= */ true)); + } + } + + public void notifyVibrationAttempt(DebugInfo vibrationDebugInfo) { + mVibrations.add(vibrationDebugInfo); + } + + @Nullable + public VibrationStepConductor clearVibrationConductor() { + synchronized (mLock) { + VibrationStepConductor conductor = mConductor; + if (conductor != null) { + mVibrations.add(conductor.getVibration().getDebugInfo()); + } + mConductor = null; + return conductor; + } + } + + public DeviceAdapter getDeviceAdapter() { + return mDeviceAdapter; + } + + public boolean maybeSetVibrationConductor(VibrationStepConductor conductor) { + synchronized (mLock) { + if (mConductor != null) { + Slog.d(TAG, "Vibration session still dispatching previous vibration," + + " new vibration ignored"); + return false; + } + mConductor = conductor; + return true; } } @@ -296,7 +349,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub } } if (shouldTriggerSessionHook) { - mManagerHooks.endSession(mSessionId, shouldAbort); + mHandler.post(() -> mManagerHooks.endSession(mSessionId, shouldAbort)); } } @@ -309,6 +362,11 @@ final class VendorVibrationSession extends IVibrationSession.Stub mEndStatusRequest = status; mEndTime = System.currentTimeMillis(); mEndUptime = SystemClock.uptimeMillis(); + if (mConductor != null) { + // Vibration is being dispatched when session end was requested, cancel it. + mConductor.notifyCancelled(new Vibration.EndInfo(status), + /* immediate= */ status != Status.FINISHED); + } if (isStarted()) { // Only trigger "finishing" callback if session started. // Run client callback in separate thread. @@ -377,6 +435,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub static final class DebugInfoImpl implements VibrationSession.DebugInfo { private final Status mStatus; private final CallerInfo mCallerInfo; + private final List<DebugInfo> mVibrations; private final long mCreateUptime; private final long mCreateTime; @@ -385,7 +444,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub private final long mDurationMs; DebugInfoImpl(Status status, CallerInfo callerInfo, long createUptime, long createTime, - long startTime, long endUptime, long endTime) { + long startTime, long endUptime, long endTime, List<DebugInfo> vibrations) { mStatus = status; mCallerInfo = callerInfo; mCreateUptime = createUptime; @@ -393,6 +452,7 @@ final class VendorVibrationSession extends IVibrationSession.Stub mStartTime = startTime; mEndTime = endTime; mDurationMs = endUptime > 0 ? endUptime - createUptime : -1; + mVibrations = vibrations == null ? new ArrayList<>() : new ArrayList<>(vibrations); } @Override @@ -418,6 +478,9 @@ final class VendorVibrationSession extends IVibrationSession.Stub @Override public void logMetrics(VibratorFrameworkStatsLogger statsLogger) { + for (DebugInfo vibration : mVibrations) { + vibration.logMetrics(statsLogger); + } } @Override @@ -448,6 +511,14 @@ final class VendorVibrationSession extends IVibrationSession.Stub pw.println("endTime = " + (mEndTime == 0 ? null : formatTime(mEndTime, /*includeDate=*/ true))); pw.println("callerInfo = " + mCallerInfo); + + pw.println("vibrations:"); + pw.increaseIndent(); + for (DebugInfo vibration : mVibrations) { + vibration.dump(pw); + } + pw.decreaseIndent(); + pw.decreaseIndent(); } @@ -477,6 +548,12 @@ final class VendorVibrationSession extends IVibrationSession.Stub " | %s (uid=%d, deviceId=%d) | reason: %s", mCallerInfo.opPkg, mCallerInfo.uid, mCallerInfo.deviceId, mCallerInfo.reason); pw.println(timingsStr + paramStr + audioUsageStr + callerStr); + + pw.increaseIndent(); + for (DebugInfo vibration : mVibrations) { + vibration.dumpCompact(pw); + } + pw.decreaseIndent(); } @Override @@ -487,7 +564,8 @@ final class VendorVibrationSession extends IVibrationSession.Stub /* includeDate= */ true)) + ", durationMs: " + mDurationMs + ", status: " + mStatus.name().toLowerCase(Locale.ROOT) - + ", callerInfo: " + mCallerInfo; + + ", callerInfo: " + mCallerInfo + + ", vibrations: " + mVibrations; } } } diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java index 1030df692543..cc163db4dc36 100644 --- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java +++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java @@ -106,7 +106,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service"; private static final String VIBRATOR_CONTROL_SERVICE = "android.frameworks.vibrator.IVibratorControlService/default"; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; private static final VibrationAttributes DEFAULT_ATTRIBUTES = new VibrationAttributes.Builder().build(); private static final int ATTRIBUTES_ALL_BYPASS_FLAGS = @@ -610,6 +610,11 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_ERROR_TOKEN); return null; } + enforceUpdateAppOpsStatsPermission(uid); + if (!isEffectValid(effect)) { + logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_UNSUPPORTED); + return null; + } if (effect.hasVendorEffects()) { if (!Flags.vendorVibrationEffects()) { Slog.e(TAG, "vibrate; vendor effects feature disabled"); @@ -622,11 +627,6 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { return null; } } - enforceUpdateAppOpsStatsPermission(uid); - if (!isEffectValid(effect)) { - logAndRecordVibrationAttempt(effect, callerInfo, Status.IGNORED_UNSUPPORTED); - return null; - } // Create Vibration.Stats as close to the received request as possible, for tracking. SingleVibrationSession session = new SingleVibrationSession(token, callerInfo, effect); HalVibration vib = session.getVibration(); @@ -658,6 +658,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { // If not ignored so far then try to start this vibration. if (ignoreStatus == null) { + // TODO(b/378492007): Investigate if we can move this around AppOpsManager calls final long ident = Binder.clearCallingIdentity(); try { if (mCurrentSession != null) { @@ -703,6 +704,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { if (DEBUG) { Slog.d(TAG, "Canceling vibration"); } + // TODO(b/378492007): Investigate if we can move this around AppOpsManager calls final long ident = Binder.clearCallingIdentity(); try { // TODO(b/370948466): investigate why token not checked on external vibrations. @@ -762,8 +764,18 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { vibratorIds = new int[0]; } enforceUpdateAppOpsStatsPermission(uid); + + // Create session with adapter that only uses the session vibrators. + SparseArray<VibratorController> sessionVibrators = new SparseArray<>(vibratorIds.length); + for (int vibratorId : vibratorIds) { + VibratorController controller = mVibrators.get(vibratorId); + if (controller != null) { + sessionVibrators.put(vibratorId, controller); + } + } + DeviceAdapter deviceAdapter = new DeviceAdapter(mVibrationSettings, sessionVibrators); VendorVibrationSession session = new VendorVibrationSession(callerInfo, mHandler, - mVendorVibrationSessionCallbacks, vibratorIds, callback); + mVendorVibrationSessionCallbacks, deviceAdapter, callback); if (attrs.isFlagSet(VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) { // Force update of user settings before checking if this vibration effect should @@ -787,12 +799,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { ignoreStatus = Status.IGNORED_UNSUPPORTED; } - // Check if any vibrator ID was requested. - if (ignoreStatus == null && vibratorIds.length == 0) { - if (DEBUG) { - Slog.d(TAG, "Empty vibrator ids to start session, ignoring request"); + // Check if vibrator IDs requested are available. + if (ignoreStatus == null) { + if (vibratorIds.length == 0 + || vibratorIds.length != deviceAdapter.getAvailableVibratorIds().length) { + Slog.e(TAG, "Bad vibrator ids to start session, ignoring request." + + " requested=" + Arrays.toString(vibratorIds) + + " available=" + Arrays.toString(mVibratorIds)); + ignoreStatus = Status.IGNORED_UNSUPPORTED; } - ignoreStatus = Status.IGNORED_UNSUPPORTED; } // Check if user settings or DnD is set to ignore this session. @@ -810,6 +825,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } if (ignoreStatus == null) { + // TODO(b/378492007): Investigate if we can move this around AppOpsManager calls final long ident = Binder.clearCallingIdentity(); try { // If not ignored so far then stop ongoing sessions before starting this one. @@ -839,22 +855,40 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { private Status startVendorSessionLocked(VendorVibrationSession session) { Trace.traceBegin(TRACE_TAG_VIBRATOR, "startSessionLocked"); try { + long sessionId = session.getSessionId(); + if (DEBUG) { + Slog.d(TAG, "Starting session " + sessionId + " in HAL"); + } if (session.isEnded()) { // Session already ended, possibly cancelled by app cancellation signal. return session.getStatus(); } - if (!session.linkToDeath()) { - return Status.IGNORED_ERROR_TOKEN; - } - if (!mNativeWrapper.startSession(session.getSessionId(), session.getVibratorIds())) { - Slog.e(TAG, "Error starting session " + session.getSessionId() - + " on vibrators " + Arrays.toString(session.getVibratorIds())); - session.unlinkToDeath(); - return Status.IGNORED_UNSUPPORTED; + int mode = startAppOpModeLocked(session.getCallerInfo()); + switch (mode) { + case AppOpsManager.MODE_ALLOWED: + Trace.asyncTraceBegin(TRACE_TAG_VIBRATOR, "vibration", 0); + // Make sure mCurrentVibration is set while triggering the HAL. + mCurrentSession = session; + if (!session.linkToDeath()) { + mCurrentSession = null; + return Status.IGNORED_ERROR_TOKEN; + } + if (!mNativeWrapper.startSession(sessionId, session.getVibratorIds())) { + Slog.e(TAG, "Error starting session " + sessionId + " on vibrators " + + Arrays.toString(session.getVibratorIds())); + session.unlinkToDeath(); + mCurrentSession = null; + return Status.IGNORED_UNSUPPORTED; + } + session.notifyStart(); + return null; + case AppOpsManager.MODE_ERRORED: + Slog.w(TAG, "Start AppOpsManager operation errored for uid " + + session.getCallerInfo().uid); + return Status.IGNORED_ERROR_APP_OPS; + default: + return Status.IGNORED_APP_OPS; } - session.notifyStart(); - mCurrentSession = session; - return null; } finally { Trace.traceEnd(TRACE_TAG_VIBRATOR); } @@ -1045,6 +1079,9 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @GuardedBy("mLock") @Nullable private Status startVibrationOnThreadLocked(SingleVibrationSession session) { + if (DEBUG) { + Slog.d(TAG, "Starting vibration " + session.getVibration().id + " on thread"); + } VibrationStepConductor conductor = createVibrationStepConductor(session.getVibration()); session.setVibrationConductor(conductor); int mode = startAppOpModeLocked(session.getCallerInfo()); @@ -1080,12 +1117,18 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { mNextSession = null; Status errorStatus = startVibrationOnThreadLocked(session); if (errorStatus != null) { + if (DEBUG) { + Slog.d(TAG, "Error starting next vibration " + session.getVibration().id); + } endSessionLocked(session, errorStatus); } } else if (mNextSession instanceof VendorVibrationSession session) { mNextSession = null; Status errorStatus = startVendorSessionLocked(session); if (errorStatus != null) { + if (DEBUG) { + Slog.d(TAG, "Error starting next session " + session.getSessionId()); + } endSessionLocked(session, errorStatus); } } // External vibrations cannot be started asynchronously. @@ -1103,6 +1146,16 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } private VibrationStepConductor createVibrationStepConductor(HalVibration vib) { + return createVibrationStepConductor(vib, mDeviceAdapter, /* isInSession= */ false); + } + + private VibrationStepConductor createSessionVibrationStepConductor(HalVibration vib, + DeviceAdapter deviceAdapter) { + return createVibrationStepConductor(vib, deviceAdapter, /* isInSession= */ true); + } + + private VibrationStepConductor createVibrationStepConductor(HalVibration vib, + DeviceAdapter deviceAdapter, boolean isInSession) { CompletableFuture<Void> requestVibrationParamsFuture = null; if (Flags.adaptiveHapticsEnabled() @@ -1114,8 +1167,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { mVibrationSettings.getRequestVibrationParamsTimeoutMs()); } - return new VibrationStepConductor(vib, /* isInSession= */ false, mVibrationSettings, - mDeviceAdapter, mVibrationScaler, mFrameworkStatsLogger, + return new VibrationStepConductor(vib, isInSession, mVibrationSettings, + deviceAdapter, mVibrationScaler, mFrameworkStatsLogger, requestVibrationParamsFuture, mVibrationThreadCallbacks); } @@ -1136,18 +1189,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { private void logAndRecordVibrationAttempt(@Nullable CombinedVibration effect, CallerInfo callerInfo, Status status) { - logAndRecordVibration( - new Vibration.DebugInfoImpl(status, callerInfo, - VibrationStats.StatsInfo.findVibrationType(effect), new VibrationStats(), - effect, /* originalEffect= */ null, VibrationScaler.SCALE_NONE, - VibrationScaler.ADAPTIVE_SCALE_NONE)); + logAndRecordVibration(createVibrationAttemptDebugInfo(effect, callerInfo, status)); } private void logAndRecordSessionAttempt(CallerInfo callerInfo, Status status) { logAndRecordVibration( new VendorVibrationSession.DebugInfoImpl(status, callerInfo, SystemClock.uptimeMillis(), System.currentTimeMillis(), - /* startTime= */ 0, /* endUptime= */ 0, /* endTime= */ 0)); + /* startTime= */ 0, /* endUptime= */ 0, /* endTime= */ 0, + /* vibrations= */ null)); } private void logAndRecordVibration(DebugInfo info) { @@ -1156,6 +1206,14 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { mVibratorManagerRecords.record(info); } + private DebugInfo createVibrationAttemptDebugInfo(@Nullable CombinedVibration effect, + CallerInfo callerInfo, Status status) { + return new Vibration.DebugInfoImpl(status, callerInfo, + VibrationStats.StatsInfo.findVibrationType(effect), new VibrationStats(), + effect, /* originalEffect= */ null, VibrationScaler.SCALE_NONE, + VibrationScaler.ADAPTIVE_SCALE_NONE); + } + private void logVibrationStatus(int uid, VibrationAttributes attrs, Status status) { switch (status) { case IGNORED_BACKGROUND: @@ -1766,25 +1824,35 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { Trace.traceBegin(TRACE_TAG_VIBRATOR, "onVibrationThreadReleased"); try { synchronized (mLock) { - if (!(mCurrentSession instanceof SingleVibrationSession session)) { + if (mCurrentSession instanceof SingleVibrationSession session) { + if (Build.IS_DEBUGGABLE && (session.getVibration().id != vibrationId)) { + Slog.wtf(TAG, TextUtils.formatSimple( + "VibrationId mismatch on vibration thread release." + + " expected=%d, released=%d", + session.getVibration().id, vibrationId)); + } + finishAppOpModeLocked(mCurrentSession.getCallerInfo()); + clearCurrentSessionLocked(); + Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); + // Start next vibration if it's waiting for the thread. + maybeStartNextSessionLocked(); + } else if (mCurrentSession instanceof VendorVibrationSession session) { + VibrationStepConductor conductor = session.clearVibrationConductor(); if (Build.IS_DEBUGGABLE) { - Slog.wtf(TAG, "VibrationSession invalid on vibration thread release." - + " currentSession=" + mCurrentSession); + if (conductor == null) { + Slog.wtf(TAG, "Vendor session without ongoing vibration on" + + " thread release. currentSession=" + mCurrentSession); + } else if (conductor.getVibration().id != vibrationId) { + Slog.wtf(TAG, TextUtils.formatSimple( + "VibrationId mismatch on vibration thread release." + + " expected=%d, released=%d", + conductor.getVibration().id, vibrationId)); + } } - // Only single vibration sessions are ended by thread being released. Abort. - return; + } else if (Build.IS_DEBUGGABLE) { + Slog.wtf(TAG, "VibrationSession invalid on vibration thread release." + + " currentSession=" + mCurrentSession); } - if (Build.IS_DEBUGGABLE && (session.getVibration().id != vibrationId)) { - Slog.wtf(TAG, TextUtils.formatSimple( - "VibrationId mismatch on vibration thread release." - + " expected=%d, released=%d", - session.getVibration().id, vibrationId)); - } - finishAppOpModeLocked(mCurrentSession.getCallerInfo()); - clearCurrentSessionLocked(); - Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); - // Start next vibration if it's waiting for the thread. - maybeStartNextSessionLocked(); } } finally { Trace.traceEnd(TRACE_TAG_VIBRATOR); @@ -1839,6 +1907,86 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { implements VendorVibrationSession.VibratorManagerHooks { @Override + public void vibrate(long sessionId, CallerInfo callerInfo, CombinedVibration effect) { + if (DEBUG) { + Slog.d(TAG, "Vibration session " + sessionId + " vibration requested"); + } + Trace.traceBegin(TRACE_TAG_VIBRATOR, "sessionVibrate"); + try { + synchronized (mLock) { + if (!(mCurrentSession instanceof VendorVibrationSession session)) { + if (Build.IS_DEBUGGABLE) { + Slog.wtf(TAG, "VibrationSession invalid on session vibrate." + + " currentSession=" + mCurrentSession); + } + // Only vendor vibration sessions can handle this call. Abort. + return; + } + if (session.getSessionId() != sessionId) { + if (Build.IS_DEBUGGABLE) { + Slog.wtf(TAG, TextUtils.formatSimple( + "SessionId mismatch on vendor vibration session vibrate." + + " expected=%d, released=%d", + session.getSessionId(), sessionId)); + } + // Only the ongoing vendor vibration sessions can handle this call. Abort. + return; + } + if (session.wasEndRequested()) { + if (DEBUG) { + Slog.d(TAG, "session vibrate; session is ending, vibration ignored"); + } + session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect, + callerInfo, Status.IGNORED_ERROR_SCHEDULING)); + return; + } + if (!isEffectValid(effect)) { + session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect, + callerInfo, Status.IGNORED_UNSUPPORTED)); + return; + } + if (effect.getDuration() == Long.MAX_VALUE) { + // Repeating effects cannot be played by the service in a session. + session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect, + callerInfo, Status.IGNORED_UNSUPPORTED)); + return; + } + // Create Vibration.Stats as close to the request as possible, for tracking. + HalVibration vib = new HalVibration(callerInfo, effect); + vib.fillFallbacks(mVibrationSettings::getFallbackEffect); + + if (callerInfo.attrs.isFlagSet( + VibrationAttributes.FLAG_INVALIDATE_SETTINGS_CACHE)) { + // Force update of user settings before checking if this vibration effect + // should be ignored or scaled. + mVibrationSettings.update(); + } + + if (DEBUG) { + Slog.d(TAG, "Starting vibrate for vibration " + vib.id + + " in session " + sessionId); + } + + VibrationStepConductor conductor = + createSessionVibrationStepConductor(vib, session.getDeviceAdapter()); + if (session.maybeSetVibrationConductor(conductor)) { + if (!mVibrationThread.runVibrationOnVibrationThread(conductor)) { + // Shouldn't happen. The method call already logs. + vib.end(new Vibration.EndInfo(Status.IGNORED_ERROR_SCHEDULING)); + session.clearVibrationConductor(); // Rejected by thread, clear it. + } + } else { + // Cannot set vibration in session, log failed attempt. + session.notifyVibrationAttempt(createVibrationAttemptDebugInfo(effect, + callerInfo, Status.IGNORED_ERROR_SCHEDULING)); + } + } + } finally { + Trace.traceEnd(TRACE_TAG_VIBRATOR); + } + } + + @Override public void endSession(long sessionId, boolean shouldAbort) { if (DEBUG) { Slog.d(TAG, "Vibration session " + sessionId @@ -1874,6 +2022,12 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { + " expected=%d, released=%d", session.getSessionId(), sessionId)); } + // Make sure all controllers in session are reset after session ended. + // This will update the vibrator state to isVibrating = false for listeners. + for (int vibratorId : session.getVibratorIds()) { + mVibrators.get(vibratorId).off(); + } + finishAppOpModeLocked(mCurrentSession.getCallerInfo()); clearCurrentSessionLocked(); // Start next vibration if it's waiting for the HAL session to be over. maybeStartNextSessionLocked(); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 6707a27d83c8..f50417d6659e 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2856,7 +2856,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void prepareForShutdown() { for (int i = 0; i < getChildCount(); i++) { - createSleepToken("shutdown", getChildAt(i).mDisplayId); + final int displayId = getChildAt(i).mDisplayId; + mWindowManager.mSnapshotController.mTaskSnapshotController + .snapshotForShutdown(displayId); + createSleepToken("shutdown", displayId); } } diff --git a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java index 1c8c245f7640..bd8e8f4008de 100644 --- a/services/core/java/com/android/server/wm/SnapshotPersistQueue.java +++ b/services/core/java/com/android/server/wm/SnapshotPersistQueue.java @@ -64,6 +64,7 @@ class SnapshotPersistQueue { private boolean mStarted; private final Object mLock = new Object(); private final UserManagerInternal mUserManagerInternal; + private boolean mShutdown; SnapshotPersistQueue() { mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); @@ -101,6 +102,16 @@ class SnapshotPersistQueue { } } + /** + * Write out everything in the queue because of shutdown. + */ + void shutdown() { + synchronized (mLock) { + mShutdown = true; + mLock.notifyAll(); + } + } + @VisibleForTesting void waitForQueueEmpty() { while (true) { @@ -193,7 +204,9 @@ class SnapshotPersistQueue { if (isReadyToWrite) { next.write(); } - SystemClock.sleep(DELAY_MS); + if (!mShutdown) { + SystemClock.sleep(DELAY_MS); + } } synchronized (mLock) { final boolean writeQueueEmpty = mWriteQueue.isEmpty(); diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 1f82cdb70b91..9fe3f7563902 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -307,6 +307,28 @@ class TaskSnapshotController extends AbsAppSnapshotController<Task, TaskSnapshot } /** + * Record task snapshots before shutdown. + */ + void snapshotForShutdown(int displayId) { + if (!com.android.window.flags.Flags.recordTaskSnapshotsBeforeShutdown()) { + return; + } + final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId); + if (displayContent == null) { + return; + } + displayContent.forAllLeafTasks(task -> { + if (task.isVisible() && !task.isActivityTypeHome()) { + final TaskSnapshot snapshot = captureSnapshot(task); + if (snapshot != null) { + mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot); + } + } + }, true /* traverseTopToBottom */); + mPersister.mSnapshotPersistQueue.shutdown(); + } + + /** * Called when screen is being turned off. */ void screenTurningOff(int displayId, ScreenOffListener listener) { diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java index 143d1b72fff9..8562bb23b30f 100644 --- a/services/core/java/com/android/server/wm/TransitionController.java +++ b/services/core/java/com/android/server/wm/TransitionController.java @@ -658,8 +658,8 @@ class TransitionController { } // Always allow WindowState to assign layers since it won't affect transition. return wc.asWindowState() != null || (!isPlaying() - // Don't assign task while collecting. - && !(wc.asTask() != null && isCollecting())); + // Don't assign task or display area layers while collecting. + && !((wc.asTask() != null || wc.asDisplayArea() != null) && isCollecting())); } @WindowConfiguration.WindowingMode diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 54b257cff11d..8268cae12e3d 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1022,12 +1022,12 @@ public class WindowManagerService extends IWindowManager.Stub return; } - final boolean disableSecureWindows; + boolean disableSecureWindows; try { disableSecureWindows = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.DISABLE_SECURE_WINDOWS, 0) != 0; } catch (Settings.SettingNotFoundException e) { - return; + disableSecureWindows = false; } if (mDisableSecureWindows == disableSecureWindows) { return; diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index ead12826c263..091896590b6b 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -788,7 +788,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub deferResume = false; // Already calls ensureActivityConfig mService.mRootWindowContainer.ensureActivitiesVisible(); - mService.mRootWindowContainer.resumeFocusedTasksTopActivities(); + if (!mService.mRootWindowContainer.resumeFocusedTasksTopActivities()) { + mService.mTaskSupervisor.updateTopResumedActivityIfNeeded("endWCT-effects"); + } } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) { for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { haveConfigChanges.valueAt(i).forAllActivities(r -> { @@ -886,7 +888,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub if (windowingMode > -1) { if (mService.isInLockTaskMode() - && WindowConfiguration.inMultiWindowMode(windowingMode)) { + && WindowConfiguration.inMultiWindowMode(windowingMode) + && !container.isEmbedded()) { Slog.w(TAG, "Dropping unsupported request to set multi-window windowing mode" + " during locked task mode."); return effects; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java index b982098fefa4..76d16e19e774 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java @@ -371,6 +371,9 @@ class ActiveAdmin { } ActiveAdmin(int userId, boolean permissionBased) { + if (Flags.activeAdminCleanup()) { + throw new UnsupportedOperationException("permission based admin no longer supported"); + } if (permissionBased == false) { throw new IllegalArgumentException("Can only pass true for permissionBased admin"); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java index 395ea9176877..c937e10a28ce 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyData.java @@ -21,6 +21,7 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManager; +import android.app.admin.flags.Flags; import android.content.ComponentName; import android.os.FileUtils; import android.os.PersistableBundle; @@ -124,17 +125,18 @@ class DevicePolicyData { final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>(); final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>(); - // Some DevicePolicyManager APIs can be called by (1) a DPC or (2) an app with permissions that - // isn't a DPC. For the latter, the caller won't have to provide a ComponentName and won't be - // mapped to an ActiveAdmin. This permission-based admin should be used to persist policies - // set by the permission-based caller. This admin should not be added to mAdminMap or mAdminList - // since a lot of methods in DPMS assume the ActiveAdmins here have a valid ComponentName. - // Instead, use variants of DPMS active admin getters to include the permission-based admin. + /** + * @deprecated Do not use. Policies set by permission holders must go into DevicePolicyEngine. + */ + @Deprecated ActiveAdmin mPermissionBasedAdmin; // Create or get the permission-based admin. The permission-based admin will not have a // DeviceAdminInfo or ComponentName. ActiveAdmin createOrGetPermissionBasedAdmin(int userId) { + if (Flags.activeAdminCleanup()) { + throw new UnsupportedOperationException("permission based admin no longer supported"); + } if (mPermissionBasedAdmin == null) { mPermissionBasedAdmin = new ActiveAdmin(userId, /* permissionBased= */ true); } @@ -147,7 +149,7 @@ class DevicePolicyData { // This is the list of component allowed to start lock task mode. List<String> mLockTaskPackages = new ArrayList<>(); - /** @deprecated moved to {@link ActiveAdmin#protectedPackages}. */ + /** @deprecated moved to DevicePolicyEngine. */ @Deprecated @Nullable List<String> mUserControlDisabledPackages; @@ -280,7 +282,7 @@ class DevicePolicyData { } } - if (policyData.mPermissionBasedAdmin != null) { + if (!Flags.activeAdminCleanup() && policyData.mPermissionBasedAdmin != null) { out.startTag(null, "permission-based-admin"); policyData.mPermissionBasedAdmin.writeToXml(out); out.endTag(null, "permission-based-admin"); @@ -521,7 +523,8 @@ class DevicePolicyData { } catch (RuntimeException e) { Slogf.w(TAG, e, "Failed loading admin %s", name); } - } else if ("permission-based-admin".equals(tag)) { + } else if (!Flags.activeAdminCleanup() && "permission-based-admin".equals(tag)) { + ActiveAdmin ap = new ActiveAdmin(policy.mUserId, /* permissionBased= */ true); ap.readFromXml(parser, /* overwritePolicies= */ false); policy.mPermissionBasedAdmin = ap; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index dff34389eb89..6292cbfad00b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -376,6 +376,7 @@ import android.app.backup.IBackupManager; import android.app.compat.CompatChanges; import android.app.role.OnRoleHoldersChangedListener; import android.app.role.RoleManager; +import android.app.supervision.SupervisionManagerInternal; import android.app.trust.TrustManager; import android.app.usage.UsageStatsManagerInternal; import android.compat.annotation.ChangeId; @@ -504,6 +505,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.LocalePicker; import com.android.internal.infra.AndroidFuture; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.net.NetworkUtilsInternal; import com.android.internal.notification.SystemNotificationChannels; @@ -715,24 +717,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { SECURE_SETTINGS_DEVICEOWNER_ALLOWLIST.add(Settings.Secure.LOCATION_MODE); GLOBAL_SETTINGS_ALLOWLIST = new ArraySet<>(); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.ADB_ENABLED); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.ADB_WIFI_ENABLED); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.AUTO_TIME); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.AUTO_TIME_ZONE); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.DATA_ROAMING); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.WIFI_SLEEP_POLICY); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.PRIVATE_DNS_MODE); - GLOBAL_SETTINGS_ALLOWLIST.add(Settings.Global.PRIVATE_DNS_SPECIFIER); + GLOBAL_SETTINGS_ALLOWLIST.add(Global.ADB_ENABLED); + GLOBAL_SETTINGS_ALLOWLIST.add(Global.ADB_WIFI_ENABLED); + GLOBAL_SETTINGS_ALLOWLIST.add(Global.AUTO_TIME); + GLOBAL_SETTINGS_ALLOWLIST.add(Global.AUTO_TIME_ZONE); + GLOBAL_SETTINGS_ALLOWLIST.add(Global.DATA_ROAMING); + GLOBAL_SETTINGS_ALLOWLIST.add(Global.USB_MASS_STORAGE_ENABLED); + GLOBAL_SETTINGS_ALLOWLIST.add(Global.WIFI_SLEEP_POLICY); + GLOBAL_SETTINGS_ALLOWLIST.add(Global.STAY_ON_WHILE_PLUGGED_IN); + GLOBAL_SETTINGS_ALLOWLIST.add(Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN); + GLOBAL_SETTINGS_ALLOWLIST.add(Global.PRIVATE_DNS_MODE); + GLOBAL_SETTINGS_ALLOWLIST.add(PRIVATE_DNS_SPECIFIER); GLOBAL_SETTINGS_DEPRECATED = new ArraySet<>(); - GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.BLUETOOTH_ON); - GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED); - GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.MODE_RINGER); - GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.NETWORK_PREFERENCE); - GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.WIFI_ON); + GLOBAL_SETTINGS_DEPRECATED.add(Global.BLUETOOTH_ON); + GLOBAL_SETTINGS_DEPRECATED.add(Global.DEVELOPMENT_SETTINGS_ENABLED); + GLOBAL_SETTINGS_DEPRECATED.add(Global.MODE_RINGER); + GLOBAL_SETTINGS_DEPRECATED.add(Global.NETWORK_PREFERENCE); + GLOBAL_SETTINGS_DEPRECATED.add(Global.WIFI_ON); SYSTEM_SETTINGS_ALLOWLIST = new ArraySet<>(); SYSTEM_SETTINGS_ALLOWLIST.add(Settings.System.SCREEN_BRIGHTNESS); @@ -775,7 +777,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Strings logged with {@link - * com.android.internal.logging.nano.MetricsProto.MetricsEvent#PROVISIONING_ENTRY_POINT_ADB}, + * MetricsProto.MetricsEvent#PROVISIONING_ENTRY_POINT_ADB}, * {@link DevicePolicyEnums#PROVISIONING_ENTRY_POINT_ADB}, * {@link DevicePolicyEnums#SET_NETWORK_LOGGING_ENABLED} and * {@link DevicePolicyEnums#RETRIEVE_NETWORK_LOGS}. @@ -786,11 +788,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * For admin apps targeting R+, throw when the app sets password requirement * that is not taken into account at given quality. For example when quality is set - * to {@link android.app.admin.DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, it doesn't + * to {@link DevicePolicyManager#PASSWORD_QUALITY_UNSPECIFIED}, it doesn't * make sense to require certain password length. If the intent is to require a password of * certain length having at least NUMERIC quality, the admin should first call - * {@link android.app.admin.DevicePolicyManager#setPasswordQuality} and only then call - * {@link android.app.admin.DevicePolicyManager#setPasswordMinimumLength}. + * {@link DevicePolicyManager#setPasswordQuality} and only then call + * {@link DevicePolicyManager#setPasswordMinimumLength}. * * <p>Conversely when an admin app targeting R+ lowers password quality, those * requirements that stop making sense are reset to default values. @@ -801,9 +803,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Admin apps targeting Android R+ may not use - * {@link android.app.admin.DevicePolicyManager#setSecureSetting} to change the deprecated - * {@link android.provider.Settings.Secure#LOCATION_MODE} setting. Instead they should use - * {@link android.app.admin.DevicePolicyManager#setLocationEnabled}. + * {@link DevicePolicyManager#setSecureSetting} to change the deprecated + * {@link Settings.Secure#LOCATION_MODE} setting. Instead they should use + * {@link DevicePolicyManager#setLocationEnabled}. */ @ChangeId @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q) @@ -849,7 +851,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private @interface CopyAccountStatus {} /** - * Mapping of {@link android.app.admin.DevicePolicyManager.ApplicationExemptionConstants} to + * Mapping of {@link DevicePolicyManager.ApplicationExemptionConstants} to * corresponding app-ops. */ private static final Map<Integer, String> APPLICATION_EXEMPTION_CONSTANTS_TO_APP_OPS = @@ -881,11 +883,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Admin apps targeting Android S+ may not use - * {@link android.app.admin.DevicePolicyManager#setPasswordQuality} to set password quality + * {@link DevicePolicyManager#setPasswordQuality} to set password quality * on the {@code DevicePolicyManager} instance obtained by calling - * {@link android.app.admin.DevicePolicyManager#getParentProfileInstance}. + * {@link DevicePolicyManager#getParentProfileInstance}. * Instead, they should use - * {@link android.app.admin.DevicePolicyManager#setRequiredPasswordComplexity} to set + * {@link DevicePolicyManager#setRequiredPasswordComplexity} to set * coarse-grained password requirements device-wide. */ @ChangeId @@ -894,7 +896,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * For Admin Apps targeting U+ - * If {@link android.security.IKeyChainService#setGrant} is called with an alias with no + * If {@link IKeyChainService#setGrant} is called with an alias with no * existing key, throw IllegalArgumentException. */ @ChangeId @@ -926,6 +928,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final UsageStatsManagerInternal mUsageStatsManagerInternal; final TelephonyManager mTelephonyManager; final RoleManager mRoleManager; + final SupervisionManagerInternal mSupervisionManagerInternal; + private final LockPatternUtils mLockPatternUtils; private final LockSettingsInternal mLockSettingsInternal; private final DeviceAdminServiceController mDeviceAdminServiceController; @@ -1474,8 +1478,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (packageName == null || packageName.equals(adminPackage)) { if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null || mIPackageManager.getReceiverInfo(aa.info.getComponent(), - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, + MATCH_DIRECT_BOOT_AWARE + | MATCH_DIRECT_BOOT_UNAWARE, userHandle) == null) { Slogf.e(LOG_TAG, String.format( "Admin package %s not found for user %d, removing active admin", @@ -1693,7 +1697,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return getPackageManager().hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN); } - Context createContextAsUser(UserHandle user) throws PackageManager.NameNotFoundException { + Context createContextAsUser(UserHandle user) throws NameNotFoundException { final String packageName = mContext.getPackageName(); return mContext.createPackageContextAsUser(packageName, 0, user); } @@ -2005,25 +2009,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } void settingsGlobalPutStringForUser(String name, String value, int userHandle) { - Settings.Global.putStringForUser(mContext.getContentResolver(), + Global.putStringForUser(mContext.getContentResolver(), name, value, userHandle); } int settingsGlobalGetInt(String name, int def) { - return Settings.Global.getInt(mContext.getContentResolver(), name, def); + return Global.getInt(mContext.getContentResolver(), name, def); } @Nullable String settingsGlobalGetString(String name) { - return Settings.Global.getString(mContext.getContentResolver(), name); + return Global.getString(mContext.getContentResolver(), name); } void settingsGlobalPutInt(String name, int value) { - Settings.Global.putInt(mContext.getContentResolver(), name, value); + Global.putInt(mContext.getContentResolver(), name, value); } void settingsGlobalPutString(String name, String value) { - Settings.Global.putString(mContext.getContentResolver(), name, value); + Global.putString(mContext.getContentResolver(), name, value); } void settingsSystemPutStringForUser(String name, String value, int userId) { @@ -2082,6 +2086,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean isAdminInstalledCaCertAutoApproved() { return false; } + + @Nullable + SupervisionManagerInternal getSupervisionManager() { + return LocalServices.getService(SupervisionManagerInternal.class); + } } /** @@ -2113,6 +2122,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mIPermissionManager = Objects.requireNonNull(injector.getIPermissionManager()); mTelephonyManager = Objects.requireNonNull(injector.getTelephonyManager()); mRoleManager = Objects.requireNonNull(injector.getRoleManager()); + if (Flags.secondaryLockscreenApiEnabled()) { + mSupervisionManagerInternal = injector.getSupervisionManager(); + } else { + mSupervisionManagerInternal = null; + } mLocalService = new LocalService(); mLockPatternUtils = injector.newLockPatternUtils(); @@ -2234,7 +2248,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return Collections.unmodifiableSet(packageNames); } - private @Nullable String getDefaultRoleHolderPackageName(int resId) { String packageNameAndSignature = mContext.getString(resId); @@ -3194,8 +3207,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return mIPackageManager.getReceiverInfo(adminName, GET_META_DATA | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS - | PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle); + | MATCH_DIRECT_BOOT_AWARE + | MATCH_DIRECT_BOOT_UNAWARE, userHandle); } catch (RemoteException e) { // shouldn't happen. Slogf.wtf(LOG_TAG, "Error getting receiver info", e); @@ -3206,9 +3219,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new IllegalArgumentException("Unknown admin: " + adminName); } - if (!permission.BIND_DEVICE_ADMIN.equals(ai.permission)) { + if (!BIND_DEVICE_ADMIN.equals(ai.permission)) { final String message = "DeviceAdminReceiver " + adminName + " must be protected with " - + permission.BIND_DEVICE_ADMIN; + + BIND_DEVICE_ADMIN; Slogf.w(LOG_TAG, message); if (throwForMissingPermission && ai.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) { @@ -3966,7 +3979,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final int N = admins.size(); for (int i = 0; i < N; i++) { ActiveAdmin admin = admins.get(i); - if ((admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) + if (((!Flags.activeAdminCleanup() && admin.isPermissionBased) + || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) && admin.passwordExpirationTimeout > 0L && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS && admin.passwordExpirationDate > 0L) { @@ -4399,8 +4413,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final ApplicationInfo ai; try { ai = mInjector.getIPackageManager().getApplicationInfo(packageName, - (PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE), userHandle); + (MATCH_DIRECT_BOOT_AWARE + | MATCH_DIRECT_BOOT_UNAWARE), userHandle); } catch (RemoteException e) { throw new IllegalStateException(e); } @@ -5563,13 +5577,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { caller.getUserId()); Preconditions.checkArgument(!calledOnParent || isProfileOwner(caller)); - ActiveAdmin activeAdmin = admin.getActiveAdmin(); + final ActiveAdmin activeAdmin; + if (Flags.activeAdminCleanup()) { + if (admin.hasAuthority(EnforcingAdmin.DPC_AUTHORITY)) { + synchronized (getLockObject()) { + activeAdmin = getActiveAdminUncheckedLocked( + admin.getComponentName(), admin.getUserId()); + } + } else { + activeAdmin = null; + } + } else { + activeAdmin = admin.getActiveAdmin(); + } // We require the caller to explicitly clear any password quality requirements set // on the parent DPM instance, to avoid the case where password requirements are // specified in the form of quality on the parent but complexity on the profile // itself. - if (!calledOnParent) { + if (activeAdmin != null && !calledOnParent) { final boolean hasQualityRequirementsOnParent = activeAdmin.hasParentActiveAdmin() && activeAdmin.getParentActiveAdmin().mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED; @@ -5593,20 +5619,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } mInjector.binderWithCleanCallingIdentity(() -> { - // Reset the password policy. - if (calledOnParent) { - activeAdmin.getParentActiveAdmin().mPasswordPolicy = new PasswordPolicy(); - } else { - activeAdmin.mPasswordPolicy = new PasswordPolicy(); + if (activeAdmin != null) { + // Reset the password policy. + if (calledOnParent) { + activeAdmin.getParentActiveAdmin().mPasswordPolicy = new PasswordPolicy(); + } else { + activeAdmin.mPasswordPolicy = new PasswordPolicy(); + } + updatePasswordQualityCacheForUserGroup(caller.getUserId()); } + synchronized (getLockObject()) { updatePasswordValidityCheckpointLocked(caller.getUserId(), calledOnParent); } - updatePasswordQualityCacheForUserGroup(caller.getUserId()); saveSettingsLocked(caller.getUserId()); }); - DevicePolicyEventLogger .createEvent(DevicePolicyEnums.SET_PASSWORD_COMPLEXITY) .setAdmin(caller.getPackageName()) @@ -5965,7 +5993,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkCallAuthorization(admin != null, "Unauthorized caller cannot call resetPassword."); if (getTargetSdk(admin.info.getPackageName(), - userHandle) <= android.os.Build.VERSION_CODES.M) { + userHandle) <= Build.VERSION_CODES.M) { Slogf.e(LOG_TAG, "Device admin can no longer call resetPassword()"); return false; } @@ -6115,7 +6143,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (policy.mLastMaximumTimeToLock != Long.MAX_VALUE) { // Make sure KEEP_SCREEN_ON is disabled, since that // would allow bypassing of the maximum time to lock. - mInjector.settingsGlobalPutInt(Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); + mInjector.settingsGlobalPutInt(Global.STAY_ON_WHILE_PLUGGED_IN, 0); } getPowerManagerInternal().setMaximumScreenOffTimeoutFromDeviceAdmin(parentId, timeMs); }); @@ -6287,28 +6315,33 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final int callingUserId = caller.getUserId(); ComponentName adminComponent = null; synchronized (getLockObject()) { - ActiveAdmin admin; // Make sure the caller has any active admin with the right policy or // the required permission. if (Flags.lockNowCoexistence()) { - admin = enforcePermissionsAndGetEnforcingAdmin( + EnforcingAdmin enforcingAdmin = enforcePermissionsAndGetEnforcingAdmin( /* admin= */ null, /* permissions= */ new String[]{MANAGE_DEVICE_POLICY_LOCK, LOCK_DEVICE}, /* deviceAdminPolicy= */ USES_POLICY_FORCE_LOCK, caller.getPackageName(), getAffectedUser(parent) - ).getActiveAdmin(); + ); + if (Flags.activeAdminCleanup()) { + adminComponent = enforcingAdmin.getComponentName(); + } else { + ActiveAdmin admin = enforcingAdmin.getActiveAdmin(); + adminComponent = admin == null ? null : admin.info.getComponent(); + } } else { - admin = getActiveAdminOrCheckPermissionForCallerLocked( + ActiveAdmin admin = getActiveAdminOrCheckPermissionForCallerLocked( null, - DeviceAdminInfo.USES_POLICY_FORCE_LOCK, + USES_POLICY_FORCE_LOCK, parent, LOCK_DEVICE); + adminComponent = admin == null ? null : admin.info.getComponent(); } checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_LOCK_NOW); final long ident = mInjector.binderClearCallingIdentity(); try { - adminComponent = admin == null ? null : admin.info.getComponent(); if (adminComponent != null) { // For Profile Owners only, callers with only permission not allowed. if ((flags & DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY) != 0) { @@ -7443,7 +7476,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * privileged APIs. * <p> * This is done by checking that the calling package is authorized to perform the app operation - * {@link android.app.AppOpsManager#OP_MANAGE_CREDENTIALS}. + * {@link AppOpsManager#OP_MANAGE_CREDENTIALS}. * * @param caller the calling identity * @return {@code true} if the calling process is the credential management app. @@ -7453,7 +7486,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { AppOpsManager appOpsManager = mInjector.getAppOpsManager(); if (appOpsManager == null) return false; return appOpsManager.noteOpNoThrow(AppOpsManager.OP_MANAGE_CREDENTIALS, caller.getUid(), - caller.getPackageName(), null, null) == AppOpsManager.MODE_ALLOWED; + caller.getPackageName(), null, null) == MODE_ALLOWED; }); } @@ -7764,7 +7797,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public void wipeDataWithReason(String callerPackageName, int flags, @NonNull String wipeReasonForUser, boolean calledOnParentInstance, boolean factoryReset) { - if (!mHasFeature && !hasCallingOrSelfPermission(permission.MASTER_CLEAR)) { + if (!mHasFeature && !hasCallingOrSelfPermission(MASTER_CLEAR)) { return; } CallerIdentity caller = getCallerIdentity(callerPackageName); @@ -7777,7 +7810,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { USES_POLICY_WIPE_DATA, caller.getPackageName(), factoryReset ? UserHandle.USER_ALL : getAffectedUser(calledOnParentInstance)); - ActiveAdmin admin = enforcingAdmin.getActiveAdmin(); checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_WIPE_DATA); @@ -7786,10 +7818,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { calledByProfileOwnerOnOrgOwnedDevice, calledOnParentInstance); } - int userId = admin != null ? admin.getUserHandle().getIdentifier() - : caller.getUserId(); - Slogf.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser, admin, - userId); + int userId; + ActiveAdmin admin = null; + if (Flags.activeAdminCleanup()) { + userId = enforcingAdmin.getUserId(); + Slogf.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser, + enforcingAdmin, userId); + } else { + admin = enforcingAdmin.getActiveAdmin(); + userId = admin != null ? admin.getUserHandle().getIdentifier() + : caller.getUserId(); + Slogf.i(LOG_TAG, "wipeDataWithReason(%s): admin=%s, user=%d", wipeReasonForUser, admin, + userId); + } + if (calledByProfileOwnerOnOrgOwnedDevice) { // When wipeData is called on the parent instance, it implies wiping the entire device. if (calledOnParentInstance) { @@ -7810,25 +7852,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final String adminName; final ComponentName adminComp; - if (admin != null) { - if (admin.isPermissionBased) { + if (Flags.activeAdminCleanup()) { + adminComp = enforcingAdmin.getComponentName(); + adminName = adminComp != null + ? adminComp.flattenToShortString() + : enforcingAdmin.getPackageName(); + event.setAdmin(enforcingAdmin.getPackageName()); + // Not including any HSUM handling here because the "else" branch in the "flag off" + // case below is unreachable under normal circumstances and for permission-based + // callers admin won't be null. + } else { + if (admin != null) { + if (admin.isPermissionBased) { + adminComp = null; + adminName = caller.getPackageName(); + event.setAdmin(adminName); + } else { + adminComp = admin.info.getComponent(); + adminName = adminComp.flattenToShortString(); + event.setAdmin(adminComp); + } + } else { adminComp = null; - adminName = caller.getPackageName(); + adminName = mInjector.getPackageManager().getPackagesForUid(caller.getUid())[0]; + Slogf.i(LOG_TAG, "Logging wipeData() event admin as " + adminName); event.setAdmin(adminName); - } else { - adminComp = admin.info.getComponent(); - adminName = adminComp.flattenToShortString(); - event.setAdmin(adminComp); - } - } else { - adminComp = null; - adminName = mInjector.getPackageManager().getPackagesForUid(caller.getUid())[0]; - Slogf.i(LOG_TAG, "Logging wipeData() event admin as " + adminName); - event.setAdmin(adminName); - if (mInjector.userManagerIsHeadlessSystemUserMode()) { - // On headless system user mode, the call is meant to factory reset the whole - // device, otherwise the caller could simply remove the current user. - userId = UserHandle.USER_SYSTEM; + if (mInjector.userManagerIsHeadlessSystemUserMode()) { + // On headless system user mode, the call is meant to factory reset the whole + // device, otherwise the caller could simply remove the current user. + userId = UserHandle.USER_SYSTEM; + } } } event.write(); @@ -8142,7 +8195,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (getLockObject()) { if (who == null) { Preconditions.checkCallAuthorization(frpManagementAgentUid == caller.getUid() - || hasCallingPermission(permission.MASTER_CLEAR) + || hasCallingPermission(MASTER_CLEAR) || hasCallingPermission(MANAGE_DEVICE_POLICY_FACTORY_RESET), "Must be called by the FRP management agent on device"); admin = getDeviceOwnerOrProfileOwnerOfOrganizationOwnedDeviceLocked(); @@ -8316,7 +8369,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { List<ActiveAdmin> admins = getActiveAdminsForLockscreenPoliciesLocked(userHandle); for (int i = 0; i < admins.size(); i++) { ActiveAdmin admin = admins.get(i); - if (admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) { + if ((!Flags.activeAdminCleanup() && admin.isPermissionBased) + || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) { affectedUserIds.add(admin.getUserHandle().getIdentifier()); long timeout = admin.passwordExpirationTimeout; admin.passwordExpirationDate = @@ -8410,7 +8464,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { */ private int getUserIdToWipeForFailedPasswords(ActiveAdmin admin) { final int userId = admin.getUserHandle().getIdentifier(); - if (admin.isPermissionBased) { + if (!Flags.activeAdminCleanup() && admin.isPermissionBased) { return userId; } final ComponentName component = admin.info.getComponent(); @@ -8628,9 +8682,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Slogf.e(LOG_TAG, "Invalid proxy properties, ignoring: " + proxyProperties.toString()); return; } - mInjector.settingsGlobalPutString(Settings.Global.GLOBAL_HTTP_PROXY_HOST, data[0]); - mInjector.settingsGlobalPutInt(Settings.Global.GLOBAL_HTTP_PROXY_PORT, proxyPort); - mInjector.settingsGlobalPutString(Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, + mInjector.settingsGlobalPutString(Global.GLOBAL_HTTP_PROXY_HOST, data[0]); + mInjector.settingsGlobalPutInt(Global.GLOBAL_HTTP_PROXY_PORT, proxyPort); + mInjector.settingsGlobalPutString(Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList); } @@ -8751,7 +8805,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } final int rawStatus = getEncryptionStatus(); - if ((rawStatus == DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER) && legacyApp) { + if ((rawStatus == ENCRYPTION_STATUS_ACTIVE_PER_USER) && legacyApp) { return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE; } return rawStatus; @@ -8775,7 +8829,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { */ private int getEncryptionStatus() { if (mInjector.storageManagerIsFileBasedEncryptionEnabled()) { - return DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER; + return ENCRYPTION_STATUS_ACTIVE_PER_USER; } else { return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED; } @@ -8970,7 +9024,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Turn AUTO_TIME on in settings if it is required if (required) { mInjector.binderWithCleanCallingIdentity( - () -> mInjector.settingsGlobalPutInt(Settings.Global.AUTO_TIME, + () -> mInjector.settingsGlobalPutInt(Global.AUTO_TIME, 1 /* AUTO_TIME on */)); } DevicePolicyEventLogger @@ -10402,7 +10456,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mDelegationMap.clear(); policy.mStatusBarDisabled = false; policy.mSecondaryLockscreenEnabled = false; - policy.mUserProvisioningState = DevicePolicyManager.STATE_USER_UNMANAGED; + policy.mUserProvisioningState = STATE_USER_UNMANAGED; policy.mAffiliationIds.clear(); resetAffiliationCacheLocked(); policy.mLockTaskPackages.clear(); @@ -10437,7 +10491,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public int getUserProvisioningState(int userHandle) { if (!mHasFeature) { - return DevicePolicyManager.STATE_USER_UNMANAGED; + return STATE_USER_UNMANAGED; } final CallerIdentity caller = getCallerIdentity(); Preconditions.checkCallAuthorization(canManageUsers(caller) @@ -10492,7 +10546,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // ADB shell can only move directly from un-managed to finalized as part of // directly setting profile-owner or device-owner. if (getUserProvisioningState(userId) - != DevicePolicyManager.STATE_USER_UNMANAGED + != STATE_USER_UNMANAGED || newState != STATE_USER_SETUP_FINALIZED) { throw new IllegalStateException("Not allowed to change provisioning state " + "unless current provisioning state is unmanaged, and new state" @@ -10530,9 +10584,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } // Valid transitions for normal use-cases. switch (currentState) { - case DevicePolicyManager.STATE_USER_UNMANAGED: + case STATE_USER_UNMANAGED: // Can move to any state from unmanaged (except itself as an edge case).. - if (newState != DevicePolicyManager.STATE_USER_UNMANAGED) { + if (newState != STATE_USER_UNMANAGED) { return; } break; @@ -10556,7 +10610,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { break; case DevicePolicyManager.STATE_USER_PROFILE_FINALIZED: // Should only move to an unmanaged state after removing the work profile. - if (newState == DevicePolicyManager.STATE_USER_UNMANAGED) { + if (newState == STATE_USER_UNMANAGED) { return; } break; @@ -10928,7 +10982,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { UserHandle userHandle = UserHandle.of(userId); userContext = mContext.createPackageContextAsUser(packageName, /* flags= */ 0, userHandle); - } catch (PackageManager.NameNotFoundException nnfe) { + } catch (NameNotFoundException nnfe) { Slogf.w(LOG_TAG, nnfe, "%s is not installed for user %d", packageName, userId); return null; } @@ -11148,20 +11202,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean canQueryAdminPolicy(CallerIdentity caller) { - return hasCallingOrSelfPermission(permission.QUERY_ADMIN_POLICY); + return hasCallingOrSelfPermission(QUERY_ADMIN_POLICY); } private boolean hasPermission(String permission, int pid, int uid) { - return mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED; + return mContext.checkPermission(permission, pid, uid) == PERMISSION_GRANTED; } private boolean hasCallingPermission(String permission) { - return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED; + return mContext.checkCallingPermission(permission) == PERMISSION_GRANTED; } private boolean hasCallingOrSelfPermission(String permission) { return mContext.checkCallingOrSelfPermission(permission) - == PackageManager.PERMISSION_GRANTED; + == PERMISSION_GRANTED; } private boolean hasPermissionForPreflight(CallerIdentity caller, String permission) { @@ -11467,7 +11521,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private String getEncryptionStatusName(int encryptionStatus) { switch (encryptionStatus) { - case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER: + case ENCRYPTION_STATUS_ACTIVE_PER_USER: return "per-user"; case DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED: return "unsupported"; @@ -12549,7 +12603,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) { Settings.Secure.putIntForUser(mContext.getContentResolver(), - Settings.Secure.USER_SETUP_COMPLETE, 1, userHandle); + USER_SETUP_COMPLETE, 1, userHandle); } sendProvisioningCompletedBroadcast( @@ -13965,8 +14019,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { List<ResolveInfo> activitiesToEnable = mIPackageManager .queryIntentActivities(intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, + MATCH_DIRECT_BOOT_AWARE + | MATCH_DIRECT_BOOT_UNAWARE, parentUserId) .getList(); @@ -14585,34 +14639,76 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private boolean hasActiveSupervisionTestAdminLocked(@UserIdInt int userId) { + ensureLocked(); + if (mConstants.USE_TEST_ADMIN_AS_SUPERVISION_COMPONENT) { + final DevicePolicyData policy = getUserData(userId); + for (ActiveAdmin admin : policy.mAdminMap.values()) { + if (admin != null && admin.testOnlyAdmin) { + return true; + } + } + } + return false; + } + @Override public void setSecondaryLockscreenEnabled(ComponentName who, boolean enabled, PersistableBundle options) { - Objects.requireNonNull(who, "ComponentName is null"); - - // Check can set secondary lockscreen enabled - final CallerIdentity caller = getCallerIdentity(who); - Preconditions.checkCallAuthorization( - isDefaultDeviceOwner(caller) || isProfileOwner(caller)); - Preconditions.checkCallAuthorization(!isManagedProfile(caller.getUserId()), - "User %d is not allowed to call setSecondaryLockscreenEnabled", + if (Flags.secondaryLockscreenApiEnabled()) { + final CallerIdentity caller = getCallerIdentity(); + final boolean isRoleHolder = isCallerSystemSupervisionRoleHolder(caller); + synchronized (getLockObject()) { + // TODO(b/378102594): Remove access for test admins. + final boolean isTestAdmin = hasActiveSupervisionTestAdminLocked(caller.getUserId()); + Preconditions.checkCallAuthorization(isRoleHolder || isTestAdmin, + "Caller (%d) is not the SYSTEM_SUPERVISION role holder", caller.getUserId()); + } - synchronized (getLockObject()) { - // Allow testOnly admins to bypass supervision config requirement. - Preconditions.checkCallAuthorization(isAdminTestOnlyLocked(who, caller.getUserId()) - || isSupervisionComponentLocked(caller.getComponentName()), "Admin %s is not " - + "the default supervision component", caller.getComponentName()); - DevicePolicyData policy = getUserData(caller.getUserId()); - policy.mSecondaryLockscreenEnabled = enabled; - saveSettingsLocked(caller.getUserId()); + if (mSupervisionManagerInternal != null) { + mSupervisionManagerInternal.setSupervisionLockscreenEnabledForUser( + caller.getUserId(), enabled, options); + } else { + synchronized (getLockObject()) { + DevicePolicyData policy = getUserData(caller.getUserId()); + policy.mSecondaryLockscreenEnabled = enabled; + saveSettingsLocked(caller.getUserId()); + } + } + } else { + Objects.requireNonNull(who, "ComponentName is null"); + + // Check can set secondary lockscreen enabled + final CallerIdentity caller = getCallerIdentity(who); + Preconditions.checkCallAuthorization( + isDefaultDeviceOwner(caller) || isProfileOwner(caller)); + Preconditions.checkCallAuthorization(!isManagedProfile(caller.getUserId()), + "User %d is not allowed to call setSecondaryLockscreenEnabled", + caller.getUserId()); + + synchronized (getLockObject()) { + // Allow testOnly admins to bypass supervision config requirement. + Preconditions.checkCallAuthorization(isAdminTestOnlyLocked(who, caller.getUserId()) + || isSupervisionComponentLocked(caller.getComponentName()), + "Admin %s is not the default supervision component", + caller.getComponentName()); + DevicePolicyData policy = getUserData(caller.getUserId()); + policy.mSecondaryLockscreenEnabled = enabled; + saveSettingsLocked(caller.getUserId()); + } } } @Override public boolean isSecondaryLockscreenEnabled(@NonNull UserHandle userHandle) { - synchronized (getLockObject()) { - return getUserData(userHandle.getIdentifier()).mSecondaryLockscreenEnabled; + if (Flags.secondaryLockscreenApiEnabled() && mSupervisionManagerInternal != null) { + return mSupervisionManagerInternal.isSupervisionLockscreenEnabledForUser( + userHandle.getIdentifier()); + } else { + synchronized (getLockObject()) { + return getUserData(userHandle.getIdentifier()).mSecondaryLockscreenEnabled; + } } } @@ -14811,7 +14907,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (policy == null) { // We default on the power button menu, in order to be consistent with pre-P // behaviour. - return DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS; + return LOCK_TASK_FEATURE_GLOBAL_ACTIONS; } return policy.getFlags(); } @@ -14940,7 +15036,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { "Permission denial: device owners cannot update %1$s", setting)); } - if (Settings.Global.STAY_ON_WHILE_PLUGGED_IN.equals(setting)) { + if (Global.STAY_ON_WHILE_PLUGGED_IN.equals(setting)) { // ignore if it contradicts an existing policy long timeMs = getMaximumTimeToLock( who, mInjector.userHandleGetCallingUserId(), /* parent */ false); @@ -15445,7 +15541,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final int N = users.size(); for (int i = 0; i < N; i++) { int userHandle = users.get(i).id; - if (mInjector.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0, + if (mInjector.settingsSecureGetIntForUser(USER_SETUP_COMPLETE, 0, userHandle) != 0) { DevicePolicyData policy = getUserData(userHandle); if (!policy.mUserSetupComplete) { @@ -15473,7 +15569,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private class SetupContentObserver extends ContentObserver { private final Uri mUserSetupComplete = Settings.Secure.getUriFor( - Settings.Secure.USER_SETUP_COMPLETE); + USER_SETUP_COMPLETE); private final Uri mPaired = Settings.Secure.getUriFor(Settings.Secure.DEVICE_PAIRED); private final Uri mDefaultImeChanged = Settings.Secure.getUriFor( Settings.Secure.DEFAULT_INPUT_METHOD); @@ -15521,7 +15617,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private class DevicePolicyConstantsObserver extends ContentObserver { final Uri mConstantsUri = - Settings.Global.getUriFor(Settings.Global.DEVICE_POLICY_CONSTANTS); + Global.getUriFor(Global.DEVICE_POLICY_CONSTANTS); DevicePolicyConstantsObserver(Handler handler) { super(handler); @@ -15814,9 +15910,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final int uid = Objects.requireNonNull( mInjector.getPackageManager().getApplicationInfoAsUser( Objects.requireNonNull(packageName), /* flags= */ 0, userId)).uid; - return PackageManager.PERMISSION_GRANTED + return PERMISSION_GRANTED == ActivityManager.checkComponentPermission( - android.Manifest.permission.MODIFY_QUIET_MODE, uid, /* owningUid= */ + permission.MODIFY_QUIET_MODE, uid, /* owningUid= */ -1, /* exported= */ true); } catch (NameNotFoundException ex) { Slogf.w(LOG_TAG, "Cannot find the package %s to check for permissions.", @@ -15953,7 +16049,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private @Mode int findInteractAcrossProfilesResetMode(String packageName) { return getDefaultCrossProfilePackages().contains(packageName) - ? AppOpsManager.MODE_ALLOWED + ? MODE_ALLOWED : AppOpsManager.opToDefaultMode(AppOpsManager.OP_INTERACT_ACROSS_PROFILES); } @@ -16272,7 +16368,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (admin.mPasswordPolicy.quality < minPasswordQuality) { return false; } - return admin.isPermissionBased || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + return (!Flags.activeAdminCleanup() && admin.isPermissionBased) + || admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); } @Override @@ -16678,13 +16775,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (getLockObject()) { long ident = mInjector.binderClearCallingIdentity(); boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId()) - >= android.os.Build.VERSION_CODES.Q; + >= Build.VERSION_CODES.Q; try { if (!isPostQAdmin) { // Legacy admins assume that they cannot control pre-M apps if (getTargetSdk(packageName, caller.getUserId()) - < android.os.Build.VERSION_CODES.M) { + < Build.VERSION_CODES.M) { callback.sendResult(null); return; } @@ -16695,7 +16792,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (grantState == PERMISSION_GRANT_STATE_GRANTED || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED - || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) { + || grantState == PERMISSION_GRANT_STATE_DEFAULT) { AdminPermissionControlParams permissionParams = new AdminPermissionControlParams(packageName, permission, grantState, @@ -16730,26 +16827,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final List<String> SENSOR_PERMISSIONS = new ArrayList<>(); { - SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_FINE_LOCATION); - SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION); - SENSOR_PERMISSIONS.add(Manifest.permission.ACCESS_COARSE_LOCATION); - SENSOR_PERMISSIONS.add(Manifest.permission.CAMERA); - SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_AUDIO); - SENSOR_PERMISSIONS.add(Manifest.permission.ACTIVITY_RECOGNITION); - SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS); - SENSOR_PERMISSIONS.add(Manifest.permission.BACKGROUND_CAMERA); - SENSOR_PERMISSIONS.add(Manifest.permission.RECORD_BACKGROUND_AUDIO); - SENSOR_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND); + SENSOR_PERMISSIONS.add(permission.ACCESS_FINE_LOCATION); + SENSOR_PERMISSIONS.add(permission.ACCESS_BACKGROUND_LOCATION); + SENSOR_PERMISSIONS.add(permission.ACCESS_COARSE_LOCATION); + SENSOR_PERMISSIONS.add(permission.CAMERA); + SENSOR_PERMISSIONS.add(permission.RECORD_AUDIO); + SENSOR_PERMISSIONS.add(permission.ACTIVITY_RECOGNITION); + SENSOR_PERMISSIONS.add(permission.BODY_SENSORS); + SENSOR_PERMISSIONS.add(permission.BACKGROUND_CAMERA); + SENSOR_PERMISSIONS.add(permission.RECORD_BACKGROUND_AUDIO); + SENSOR_PERMISSIONS.add(permission.BODY_SENSORS_BACKGROUND); } private boolean canGrantPermission(CallerIdentity caller, String permission, String targetPackageName) { boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId()) - >= android.os.Build.VERSION_CODES.Q; + >= Build.VERSION_CODES.Q; if (!isPostQAdmin) { // Legacy admins assume that they cannot control pre-M apps if (getTargetSdk(targetPackageName, caller.getUserId()) - < android.os.Build.VERSION_CODES.M) { + < Build.VERSION_CODES.M) { return false; } } @@ -16796,7 +16893,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throws RemoteException { int granted; if (getTargetSdk(caller.getPackageName(), caller.getUserId()) - < android.os.Build.VERSION_CODES.Q) { + < Build.VERSION_CODES.Q) { // The per-Q behavior was to not check the app-ops state. granted = mIPackageManager.checkPermission(permission, packageName, userId); } else { @@ -16805,11 +16902,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (packageState == null) { Slog.w(LOG_TAG, "Can't get permission state for missing package " + packageName); - return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT; + return PERMISSION_GRANT_STATE_DEFAULT; } else if (!packageState.getUserStateOrDefault(userId).isInstalled()) { Slog.w(LOG_TAG, "Can't get permission state for uninstalled package " + packageName); - return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT; + return PERMISSION_GRANT_STATE_DEFAULT; } else { if (PermissionChecker.checkPermissionForPreflight(mContext, permission, PermissionChecker.PID_UNKNOWN, @@ -16817,7 +16914,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { != PermissionChecker.PERMISSION_GRANTED) { granted = PackageManager.PERMISSION_DENIED; } else { - granted = PackageManager.PERMISSION_GRANTED; + granted = PERMISSION_GRANTED; } } @@ -16828,11 +16925,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != PackageManager.FLAG_PERMISSION_POLICY_FIXED) { // Not controlled by policy - return DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT; + return PERMISSION_GRANT_STATE_DEFAULT; } else { // Policy controlled so return result based on permission grant state - return granted == PackageManager.PERMISSION_GRANTED - ? DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED + return granted == PERMISSION_GRANTED + ? PERMISSION_GRANT_STATE_GRANTED : DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED; } } @@ -16952,9 +17049,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } if (action != null) { switch (action) { - case DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE: + case ACTION_PROVISION_MANAGED_PROFILE: return checkManagedProfileProvisioningPreCondition(packageName, userId); - case DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE: + case ACTION_PROVISION_MANAGED_DEVICE: case DevicePolicyManager.ACTION_PROVISION_FINANCED_DEVICE: return checkDeviceOwnerProvisioningPreCondition(componentName, userId); } @@ -18301,7 +18398,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)); boolean isUserCompleted = mInjector.settingsSecureGetIntForUser( - Settings.Secure.USER_SETUP_COMPLETE, 0, userId) != 0; + USER_SETUP_COMPLETE, 0, userId) != 0; DevicePolicyData policy = getUserData(userId); policy.mUserSetupComplete = isUserCompleted; mStateCache.setDeviceProvisioned(isUserCompleted); @@ -19148,6 +19245,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private boolean isAnyResetPasswordTokenActiveForUser(int userId) { + return mDevicePolicyEngine + .getLocalPoliciesSetByAdmins(PolicyDefinition.RESET_PASSWORD_TOKEN, userId) + .values() + .stream() + .anyMatch((p) -> isResetPasswordTokenActiveForUserLocked(p.getValue(), userId)); + } + private boolean isResetPasswordTokenActiveForUserLocked( long passwordTokenHandle, int userHandle) { if (passwordTokenHandle != 0) { @@ -19924,7 +20029,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } private boolean isDeviceAB() { - return "true".equalsIgnoreCase(android.os.SystemProperties + return "true".equalsIgnoreCase(SystemProperties .get(AB_DEVICE_KEY, "")); } @@ -20191,7 +20296,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return mOwners.hasDeviceOwner() && mInjector.getIActivityManager().getLockTaskModeState() == ActivityManager.LOCK_TASK_MODE_LOCKED - && !isLockTaskFeatureEnabled(DevicePolicyManager.LOCK_TASK_FEATURE_SYSTEM_INFO) + && !isLockTaskFeatureEnabled(LOCK_TASK_FEATURE_SYSTEM_INFO) && !deviceHasKeyguard() && !inEphemeralUserSession(); } @@ -20202,7 +20307,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int lockTaskFeatures = policy == null // We default on the power button menu, in order to be consistent with pre-P // behaviour. - ? DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS + ? LOCK_TASK_FEATURE_GLOBAL_ACTIONS : policy.getFlags(); return (lockTaskFeatures & lockTaskFeature) == lockTaskFeature; } @@ -20948,7 +21053,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private boolean canHandleCheckPolicyComplianceIntent(CallerIdentity caller) { mInjector.binderWithCleanCallingIdentity(() -> { - final Intent intent = new Intent(DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE); + final Intent intent = new Intent(ACTION_CHECK_POLICY_COMPLIANCE); intent.setPackage(caller.getPackageName()); final List<ResolveInfo> handlers = mInjector.getPackageManager().queryIntentActivitiesAsUser(intent, /* flags= */ @@ -21003,6 +21108,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkCallAuthorization(isSystemUid(getCallerIdentity()), String.format(NOT_SYSTEM_CALLER_MSG, "call canProfileOwnerResetPasswordWhenLocked")); + if (Flags.resetPasswordWithTokenCoexistence()) { + return isAnyResetPasswordTokenActiveForUser(userId); + } synchronized (getLockObject()) { final ActiveAdmin poAdmin = getProfileOwnerAdminLocked(userId); DevicePolicyData policy = getUserData(userId); @@ -21154,6 +21262,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkCallAuthorization( hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)); + if (Flags.splitCreateManagedProfileEnabled()) { + return mInjector.binderWithCleanCallingIdentity(() -> { + UserHandle managedProfileUser = + createManagedProfileInternal(provisioningParams, caller); + maybeMigrateAccount(managedProfileUser.getIdentifier(), caller.getUserId(), + provisioningParams.getAccountToMigrate(), + provisioningParams.isKeepingAccountOnMigration(), callerPackage); + finalizeCreateManagedProfileInternal(provisioningParams, managedProfileUser); + return managedProfileUser; + }); + } provisioningParams.logParams(callerPackage); UserInfo userInfo = null; @@ -21247,6 +21366,130 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override + public UserHandle createManagedProfile( + @NonNull ManagedProfileProvisioningParams provisioningParams, + @NonNull String callerPackage) { + Objects.requireNonNull(provisioningParams, "provisioningParams is null"); + Objects.requireNonNull(callerPackage, "callerPackage is null"); + Objects.requireNonNull(provisioningParams.getProfileAdminComponentName(), "admin is null"); + Preconditions.checkCallAuthorization( + hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)); + CallerIdentity caller = getCallerIdentity(callerPackage); + + return mInjector.binderWithCleanCallingIdentity(() -> + createManagedProfileInternal(provisioningParams, caller)); + } + + private UserHandle createManagedProfileInternal( + @NonNull ManagedProfileProvisioningParams provisioningParams, + @NonNull CallerIdentity caller) { + provisioningParams.logParams(caller.getPackageName()); + final ComponentName admin = provisioningParams.getProfileAdminComponentName(); + final int callingUserId = caller.getUserId(); + UserInfo userInfo = null; + try { + final int result = checkProvisioningPreconditionSkipPermission( + ACTION_PROVISION_MANAGED_PROFILE, admin, callingUserId); + if (result != STATUS_OK) { + throw new ServiceSpecificException( + ERROR_PRE_CONDITION_FAILED, + "Provisioning preconditions failed with result: " + result); + } + + final long startTime = SystemClock.elapsedRealtime(); + + onCreateAndProvisionManagedProfileStarted(provisioningParams); + + userInfo = createProfileForUser(provisioningParams, callingUserId); + if (userInfo == null) { + throw new ServiceSpecificException( + ERROR_PROFILE_CREATION_FAILED, + "Error creating profile, createProfileForUserEvenWhenDisallowed " + + "returned null."); + } + resetInteractAcrossProfilesAppOps(caller.getUserId()); + logEventDuration( + DevicePolicyEnums.PLATFORM_PROVISIONING_CREATE_PROFILE_MS, + startTime, + caller.getPackageName()); + + maybeInstallDevicePolicyManagementRoleHolderInUser(userInfo.id); + installExistingAdminPackage(userInfo.id, admin.getPackageName()); + + if (!enableAdminAndSetProfileOwner(userInfo.id, caller.getUserId(), admin)) { + throw new ServiceSpecificException( + ERROR_SETTING_PROFILE_OWNER_FAILED, + "Error setting profile owner."); + } + setUserSetupComplete(userInfo.id); + startProfileForSetup(userInfo.id, caller.getPackageName()); + + if (provisioningParams.isOrganizationOwnedProvisioning()) { + synchronized (getLockObject()) { + setProfileOwnerOnOrganizationOwnedDeviceUncheckedLocked(admin, userInfo.id, + true); + } + } + return userInfo.getUserHandle(); + } catch (Exception e) { + DevicePolicyEventLogger + .createEvent(DevicePolicyEnums.PLATFORM_PROVISIONING_ERROR) + .setStrings(caller.getPackageName()) + .write(); + // In case of any errors during provisioning, remove the newly created profile. + if (userInfo != null) { + mUserManager.removeUserEvenWhenDisallowed(userInfo.id); + } + throw e; + } + } + + private UserInfo createProfileForUser(ManagedProfileProvisioningParams params, int userId) { + final Set<String> nonRequiredApps = params.isLeaveAllSystemAppsEnabled() + ? Collections.emptySet() + : mOverlayPackagesProvider.getNonRequiredApps(params.getProfileAdminComponentName(), + userId, ACTION_PROVISION_MANAGED_PROFILE); + if (nonRequiredApps.isEmpty()) { + Slogf.i(LOG_TAG, "No disallowed packages for the managed profile."); + } else { + for (String packageName : nonRequiredApps) { + Slogf.i(LOG_TAG, "Disallowed package [" + packageName + "]"); + } + } + return mUserManager.createProfileForUserEvenWhenDisallowed( + params.getProfileName(), + UserManager.USER_TYPE_PROFILE_MANAGED, + UserInfo.FLAG_DISABLED, + userId, + nonRequiredApps.toArray(new String[nonRequiredApps.size()])); + } + + @Override + public void finalizeCreateManagedProfile( + @NonNull ManagedProfileProvisioningParams provisioningParams, + @NonNull UserHandle managedProfileUser) { + Objects.requireNonNull(provisioningParams, "provisioningParams is null"); + Objects.requireNonNull(managedProfileUser, "managedProfileUser is null"); + Preconditions.checkCallAuthorization( + hasCallingOrSelfPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)); + + mInjector.binderWithCleanCallingIdentity(() -> { + finalizeCreateManagedProfileInternal(provisioningParams, managedProfileUser); + }); + } + + private void finalizeCreateManagedProfileInternal( + @NonNull ManagedProfileProvisioningParams provisioningParams, + @NonNull UserHandle managedProfileUser + ) { + onCreateAndProvisionManagedProfileCompleted(provisioningParams); + sendProvisioningCompletedBroadcast( + managedProfileUser.getIdentifier(), + ACTION_PROVISION_MANAGED_PROFILE, + provisioningParams.isLeaveAllSystemAppsEnabled()); + } + + @Override public void finalizeWorkProfileProvisioning(UserHandle managedProfileUser, Account migratedAccount) { Preconditions.checkCallAuthorization( @@ -21416,7 +21659,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void pregrantDefaultInteractAcrossProfilesAppOps(@UserIdInt int userId) { final String op = - AppOpsManager.permissionToOp(Manifest.permission.INTERACT_ACROSS_PROFILES); + AppOpsManager.permissionToOp(permission.INTERACT_ACROSS_PROFILES); for (String packageName : getConfigurableDefaultCrossProfilePackages(userId)) { if (!appOpIsDefaultOrAllowed(userId, op, packageName)) { continue; @@ -21619,7 +21862,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Slogf.i(LOG_TAG, "Account removed from the primary user."); } else { // TODO(174768447): Revisit start activity logic. - final Intent removeIntent = result.getParcelable(AccountManager.KEY_INTENT, android.content.Intent.class); + final Intent removeIntent = + result.getParcelable(AccountManager.KEY_INTENT, Intent.class); removeIntent.addFlags(FLAG_ACTIVITY_NEW_TASK); if (removeIntent != null) { Slogf.i(LOG_TAG, "Starting activity to remove account"); @@ -21915,7 +22159,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } synchronized (getLockObject()) { mInjector.settingsGlobalPutStringForUser( - Settings.Global.DEVICE_DEMO_MODE, Integer.toString(/* value= */ 1), userId); + Global.DEVICE_DEMO_MODE, Integer.toString(/* value= */ 1), userId); } setUserProvisioningState(STATE_USER_SETUP_FINALIZED, userId); @@ -22178,7 +22422,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean isDevicePotentiallyStolen(String callerPackageName) { final CallerIdentity caller = getCallerIdentity(callerPackageName); - if (!android.app.admin.flags.Flags.deviceTheftImplEnabled()) { + if (!Flags.deviceTheftImplEnabled()) { return false; } enforcePermission(QUERY_DEVICE_STOLEN_STATE, caller.getPackageName(), @@ -22214,7 +22458,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables) { Preconditions.checkCallAuthorization(hasCallingOrSelfPermission( - android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)); + permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)); Objects.requireNonNull(drawables, "drawables must be provided."); @@ -22230,7 +22474,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void resetDrawables(@NonNull List<String> drawableIds) { Preconditions.checkCallAuthorization(hasCallingOrSelfPermission( - android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)); + permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)); Objects.requireNonNull(drawableIds, "drawableIds must be provided."); @@ -22256,7 +22500,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setStrings(@NonNull List<DevicePolicyStringResource> strings) { Preconditions.checkCallAuthorization(hasCallingOrSelfPermission( - android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)); + permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)); Objects.requireNonNull(strings, "strings must be provided."); @@ -22271,7 +22515,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void resetStrings(@NonNull List<String> stringIds) { Preconditions.checkCallAuthorization(hasCallingOrSelfPermission( - android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)); + permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)); mInjector.binderWithCleanCallingIdentity(() -> { if (mDeviceManagementResourcesProvider.removeStrings(stringIds)) { @@ -22341,7 +22585,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void resetShouldAllowBypassingDevicePolicyManagementRoleQualificationState() { Preconditions.checkCallAuthorization(hasCallingOrSelfPermission( - android.Manifest.permission.MANAGE_ROLE_HOLDERS)); + permission.MANAGE_ROLE_HOLDERS)); setBypassDevicePolicyManagementRoleQualificationStateInternal( /* currentRoleHolder= */ null, /* allowBypass= */ false); } @@ -22349,7 +22593,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean shouldAllowBypassingDevicePolicyManagementRoleQualification() { Preconditions.checkCallAuthorization(hasCallingOrSelfPermission( - android.Manifest.permission.MANAGE_ROLE_HOLDERS)); + permission.MANAGE_ROLE_HOLDERS)); return mInjector.binderWithCleanCallingIdentity(() -> { if (getUserData( UserHandle.USER_SYSTEM).mBypassDevicePolicyManagementRoleQualifications) { @@ -23345,7 +23589,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return EnforcingAdmin.createDeviceAdminEnforcingAdmin(admin.info.getComponent(), userId, admin); } - admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId); + admin = Flags.activeAdminCleanup() + ? null : getUserData(userId).createOrGetPermissionBasedAdmin(userId); return EnforcingAdmin.createEnforcingAdmin(caller.getPackageName(), userId, admin); } @@ -23368,8 +23613,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - - admin = getUserData(userId).createOrGetPermissionBasedAdmin(userId); + admin = Flags.activeAdminCleanup() + ? null : getUserData(userId).createOrGetPermissionBasedAdmin(userId); return EnforcingAdmin.createEnforcingAdmin(packageName, userId, admin); } @@ -23941,7 +24186,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!isRuntimePermission(permission)) { continue; } - int grantState = DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT; + int grantState = PERMISSION_GRANT_STATE_DEFAULT; try { grantState = getPermissionGrantStateForUser( packageInfo.packageName, permission, @@ -23954,7 +24199,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Slogf.e(LOG_TAG, e, "Error retrieving permission grant state for %s " + "and %s", packageInfo.packageName, permission); } - if (grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) { + if (grantState == PERMISSION_GRANT_STATE_DEFAULT) { // Not Controlled by a policy continue; } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java index 58e3a7d236b4..1fd628a20afa 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/EnforcingAdmin.java @@ -23,6 +23,7 @@ import android.app.admin.DeviceAdminAuthority; import android.app.admin.DpcAuthority; import android.app.admin.RoleAuthority; import android.app.admin.UnknownAuthority; +import android.app.admin.flags.Flags; import android.content.ComponentName; import android.os.UserHandle; @@ -295,9 +296,17 @@ final class EnforcingAdmin { @Nullable public ActiveAdmin getActiveAdmin() { + if (Flags.activeAdminCleanup()) { + throw new UnsupportedOperationException("getActiveAdmin() no longer supported"); + } return mActiveAdmin; } + @Nullable + ComponentName getComponentName() { + return mComponentName; + } + @NonNull android.app.admin.EnforcingAdmin getParcelableAdmin() { Authority authority; diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 19b03437292f..da478f38498b 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -249,8 +249,9 @@ import com.android.server.security.AttestationVerificationManagerService; import com.android.server.security.FileIntegrityService; import com.android.server.security.KeyAttestationApplicationIdProviderService; import com.android.server.security.KeyChainSystemService; -import com.android.server.security.adaptiveauthentication.AdaptiveAuthenticationService; import com.android.server.security.advancedprotection.AdvancedProtectionService; +import com.android.server.security.authenticationpolicy.AuthenticationPolicyService; +import com.android.server.security.forensic.ForensicService; import com.android.server.security.rkp.RemoteProvisioningService; import com.android.server.selinux.SelinuxAuditLogsService; import com.android.server.sensorprivacy.SensorPrivacyService; @@ -1760,6 +1761,13 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(LogcatManagerService.class); t.traceEnd(); + if (!isWatch && !isTv && !isAutomotive + && android.security.Flags.aflApi()) { + t.traceBegin("StartForensicService"); + mSystemServiceManager.startService(ForensicService.class); + t.traceEnd(); + } + if (AppFunctionManagerConfiguration.isSupported(context)) { t.traceBegin("StartAppFunctionManager"); mSystemServiceManager.startService(AppFunctionManagerService.class); @@ -2652,8 +2660,8 @@ public final class SystemServer implements Dumpable { t.traceEnd(); if (android.adaptiveauth.Flags.enableAdaptiveAuth()) { - t.traceBegin("StartAdaptiveAuthenticationService"); - mSystemServiceManager.startService(AdaptiveAuthenticationService.class); + t.traceBegin("StartAuthenticationPolicyService"); + mSystemServiceManager.startService(AuthenticationPolicyService.class); t.traceEnd(); } @@ -2761,8 +2769,9 @@ public final class SystemServer implements Dumpable { mSystemServiceManager.startService(WEAR_MODE_SERVICE_CLASS); t.traceEnd(); - boolean enableWristOrientationService = SystemProperties.getBoolean( - "config.enable_wristorientation", false); + boolean enableWristOrientationService = + !android.server.Flags.migrateWristOrientation() + && SystemProperties.getBoolean("config.enable_wristorientation", false); if (enableWristOrientationService) { t.traceBegin("StartWristOrientationService"); mSystemServiceManager.startService(WRIST_ORIENTATION_SERVICE_CLASS); diff --git a/services/java/com/android/server/flags.aconfig b/services/java/com/android/server/flags.aconfig index e2ac22de29a4..4412968999e5 100644 --- a/services/java/com/android/server/flags.aconfig +++ b/services/java/com/android/server/flags.aconfig @@ -39,6 +39,14 @@ flag { } flag { + name: "migrate_wrist_orientation" + namespace: "wear_frameworks" + description: "Migrate wrist orientation service functionality to wear settings service" + bug: "352725980" + is_fixed_read_only: true +} + +flag { name: "allow_network_time_update_service" namespace: "wear_systems" description: "Allow NetworkTimeUpdateService on Wear" diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 4e868887ea1b..e307e529a40b 100644 --- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java +++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java @@ -144,6 +144,10 @@ public final class ProfcollectForwardingService extends SystemService { public void onBootPhase(int phase) { if (phase == PHASE_SYSTEM_SERVICES_READY) { UsbManager usbManager = getContext().getSystemService(UsbManager.class); + if (usbManager == null) { + mAdbActive = false; + return; + } mAdbActive = ((usbManager.getCurrentFunctions() & UsbManager.FUNCTION_ADB) == 1); Log.d(LOG_TAG, "ADB is " + mAdbActive + " on system startup"); } diff --git a/services/supervision/java/com/android/server/supervision/SupervisionService.java b/services/supervision/java/com/android/server/supervision/SupervisionService.java index 67e254782f6d..53a25dd454ef 100644 --- a/services/supervision/java/com/android/server/supervision/SupervisionService.java +++ b/services/supervision/java/com/android/server/supervision/SupervisionService.java @@ -21,10 +21,11 @@ import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.admin.DevicePolicyManagerInternal; import android.app.supervision.ISupervisionManager; +import android.app.supervision.SupervisionManagerInternal; import android.content.ComponentName; import android.content.Context; import android.content.pm.UserInfo; -import android.os.Bundle; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; @@ -179,8 +180,15 @@ public class SupervisionService extends ISupervisionManager.Stub { } @Override + public boolean isSupervisionLockscreenEnabledForUser(@UserIdInt int userId) { + synchronized (getLockObject()) { + return getUserDataLocked(userId).supervisionLockScreenEnabled; + } + } + + @Override public void setSupervisionLockscreenEnabledForUser( - @UserIdInt int userId, boolean enabled, @Nullable Bundle options) { + @UserIdInt int userId, boolean enabled, @Nullable PersistableBundle options) { synchronized (getLockObject()) { SupervisionUserData data = getUserDataLocked(userId); data.supervisionLockScreenEnabled = enabled; diff --git a/services/supervision/java/com/android/server/supervision/SupervisionUserData.java b/services/supervision/java/com/android/server/supervision/SupervisionUserData.java index 56162372f740..1dd48f581bf4 100644 --- a/services/supervision/java/com/android/server/supervision/SupervisionUserData.java +++ b/services/supervision/java/com/android/server/supervision/SupervisionUserData.java @@ -19,7 +19,7 @@ package com.android.server.supervision; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; -import android.os.Bundle; +import android.os.PersistableBundle; import android.util.IndentingPrintWriter; /** User specific data, used internally by the {@link SupervisionService}. */ @@ -27,7 +27,7 @@ public class SupervisionUserData { public final @UserIdInt int userId; public boolean supervisionEnabled; public boolean supervisionLockScreenEnabled; - @Nullable public Bundle supervisionLockScreenOptions; + @Nullable public PersistableBundle supervisionLockScreenOptions; public SupervisionUserData(@UserIdInt int userId) { this.userId = userId; diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java index 1be5cef28244..acd34e323dc2 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/BroadcastHelperTest.java @@ -28,6 +28,7 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -60,6 +61,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.List; @AppModeFull @AppModeNonSdkSandbox @@ -124,7 +126,8 @@ public class BroadcastHelperTest { @Test public void changeNonExportedComponent_sendPackageChangedBroadcastToSystem_withPermission() throws Exception { - changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */); + changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */, + new String[0] /* sharedPackages */); ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); verify(mMockActivityManagerInternal).broadcastIntentWithCallback( @@ -140,7 +143,8 @@ public class BroadcastHelperTest { @Test public void changeNonExportedComponent_sendPackageChangedBroadcastToApplicationItself() throws Exception { - changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */); + changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */, + new String[0] /* sharedPackages */); ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); verify(mMockActivityManagerInternal).broadcastIntentWithCallback(captor.capture(), eq(null), @@ -150,9 +154,45 @@ public class BroadcastHelperTest { assertThat(intent.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME); } + @RequiresFlagsEnabled(FLAG_REDUCE_BROADCASTS_FOR_COMPONENT_STATE_CHANGES) + @Test + public void changeNonExportedComponent_sendPackageChangedBroadcastToSharedUserIdApplications() + throws Exception { + changeComponentAndSendPackageChangedBroadcast(false /* changeExportedComponent */, + new String[]{"shared.package"} /* sharedPackages */); + + ArgumentCaptor<Intent> captorIntent = ArgumentCaptor.forClass(Intent.class); + ArgumentCaptor<String[]> captorRequiredPermissions = ArgumentCaptor.forClass( + String[].class); + verify(mMockActivityManagerInternal, times(3)).broadcastIntentWithCallback( + captorIntent.capture(), eq(null), captorRequiredPermissions.capture(), anyInt(), + eq(null), eq(null), eq(null)); + List<Intent> intents = captorIntent.getAllValues(); + List<String[]> requiredPermissions = captorRequiredPermissions.getAllValues(); + assertNotNull(intents); + assertThat(intents.size()).isEqualTo(3); + + final Intent intent1 = intents.get(0); + final String[] requiredPermission1 = requiredPermissions.get(0); + assertThat(intent1.getPackage()).isEqualTo("android"); + assertThat(requiredPermission1).isEqualTo( + new String[]{PERMISSION_PACKAGE_CHANGED_BROADCAST_ON_COMPONENT_STATE_CHANGED}); + + final Intent intent2 = intents.get(1); + final String[] requiredPermission2 = requiredPermissions.get(1); + assertThat(intent2.getPackage()).isEqualTo(PACKAGE_CHANGED_TEST_PACKAGE_NAME); + assertThat(requiredPermission2).isNull(); + + final Intent intent3 = intents.get(2); + final String[] requiredPermission3 = requiredPermissions.get(2); + assertThat(intent3.getPackage()).isEqualTo("shared.package"); + assertThat(requiredPermission3).isNull(); + } + @Test public void changeExportedComponent_sendPackageChangedBroadcastToAll() throws Exception { - changeComponentAndSendPackageChangedBroadcast(true /* changeExportedComponent */); + changeComponentAndSendPackageChangedBroadcast(true /* changeExportedComponent */, + new String[0] /* sharedPackages */); ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); verify(mMockActivityManagerInternal).broadcastIntentWithCallback(captor.capture(), eq(null), @@ -162,11 +202,14 @@ public class BroadcastHelperTest { assertNull(intent.getPackage()); } - private void changeComponentAndSendPackageChangedBroadcast(boolean changeExportedComponent) { + private void changeComponentAndSendPackageChangedBroadcast(boolean changeExportedComponent, + String[] sharedPackages) { when(mMockSnapshot.getPackageStateInternal(eq(PACKAGE_CHANGED_TEST_PACKAGE_NAME), anyInt())).thenReturn(mMockPackageStateInternal); when(mMockSnapshot.isInstantAppInternal(any(), anyInt(), anyInt())).thenReturn(false); when(mMockSnapshot.getVisibilityAllowLists(any(), any())).thenReturn(null); + when(mMockSnapshot.getSharedUserPackagesForPackage(eq(PACKAGE_CHANGED_TEST_PACKAGE_NAME), + anyInt())).thenReturn(sharedPackages); when(mMockPackageStateInternal.getPkg()).thenReturn(mMockAndroidPackageInternal); when(mMockParsedActivity.getClassName()).thenReturn( diff --git a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java index 08155c7b3f98..9772ef929eae 100644 --- a/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java +++ b/services/tests/VpnTests/java/com/android/server/connectivity/VpnTest.java @@ -2380,10 +2380,14 @@ public class VpnTest extends VpnTestBase { @Test public void doTestMigrateIkeSession_Vcn() throws Exception { final int expectedKeepalive = 2097; // Any unlikely number will do - final NetworkCapabilities vcnNc = new NetworkCapabilities.Builder() - .addTransportType(TRANSPORT_CELLULAR) - .setTransportInfo(new VcnTransportInfo(TEST_SUB_ID, expectedKeepalive)) - .build(); + final NetworkCapabilities vcnNc = + new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .setTransportInfo( + new VcnTransportInfo.Builder() + .setMinUdpPort4500NatTimeoutSeconds(expectedKeepalive) + .build()) + .build(); final Ikev2VpnProfile ikev2VpnProfile = makeIkeV2VpnProfile( true /* isAutomaticIpVersionSelectionEnabled */, true /* isAutomaticNattKeepaliveTimerEnabled */, diff --git a/services/tests/apexsystemservices/services/Android.bp b/services/tests/apexsystemservices/services/Android.bp index 477ea4cdad37..70d84dcf6007 100644 --- a/services/tests/apexsystemservices/services/Android.bp +++ b/services/tests/apexsystemservices/services/Android.bp @@ -17,4 +17,5 @@ java_library { ], visibility: ["//frameworks/base/services/tests/apexsystemservices:__subpackages__"], apex_available: ["//apex_available:anyapex"], + compile_dex: true, } diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt b/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt index 9ea7ea7ef23d..56e4048c842e 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt +++ b/services/tests/displayservicetests/src/com/android/server/display/mode/SystemRequestObserverTest.kt @@ -27,6 +27,7 @@ import org.junit.runner.RunWith import org.mockito.junit.MockitoJUnit import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.clearInvocations import org.mockito.kotlin.doThrow import org.mockito.kotlin.eq import org.mockito.kotlin.mock @@ -149,6 +150,29 @@ class SystemRequestObserverTest { } @Test + fun testTokenUnlinkToDeath_noVotes() { + val systemRequestObserver = SystemRequestObserver(storage) + + systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null) + + verify(mockToken, never()).unlinkToDeath(any(), eq(0)) + } + + @Test + fun testTokenUnlinkToDeath_removedVotes() { + val systemRequestObserver = SystemRequestObserver(storage) + val requestedModes = intArrayOf(1, 2, 3) + + systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, requestedModes) + systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null) + clearInvocations(mockToken) + + systemRequestObserver.requestDisplayModes(mockToken, DISPLAY_ID, null) + + verify(mockToken, never()).unlinkToDeath(any(), eq(0)) + } + + @Test fun testTokenUnlinkToDeathNotCalled_votesForOtherDisplayInStorage() { val systemRequestObserver = SystemRequestObserver(storage) val requestedModes = intArrayOf(1, 2, 3) diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 30de0e8c7981..8dc8c14f8948 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -67,7 +67,6 @@ import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHARGING import static com.android.server.alarm.AlarmManagerService.AlarmHandler.CHECK_EXACT_ALARM_PERMISSION_ON_UPDATE; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REFRESH_EXACT_ALARM_CANDIDATES; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_ALARMS; -import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.REMOVE_FOR_CANCELED; import static com.android.server.alarm.AlarmManagerService.AlarmHandler.TEMPORARY_QUOTA_CHANGED; import static com.android.server.alarm.AlarmManagerService.Constants.KEY_ALLOW_WHILE_IDLE_COMPAT_QUOTA; @@ -152,7 +151,6 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.DisableFlags; -import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.util.FlagSetException; @@ -436,8 +434,7 @@ public final class AlarmManagerServiceTest { */ private void disableFlagsNotSetByAnnotation() { try { - mSetFlagsRule.disableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS, - Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS); + mSetFlagsRule.disableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS); } catch (FlagSetException fse) { // Expected if the test about to be run requires this enabled. } @@ -523,13 +520,11 @@ public final class AlarmManagerServiceTest { mService.onStart(); - if (Flags.useFrozenStateToDropListenerAlarms()) { - final ArgumentCaptor<ActivityManager.UidFrozenStateChangedCallback> frozenCaptor = - ArgumentCaptor.forClass(ActivityManager.UidFrozenStateChangedCallback.class); - verify(mActivityManager).registerUidFrozenStateChangedCallback( - any(HandlerExecutor.class), frozenCaptor.capture()); - mUidFrozenStateCallback = frozenCaptor.getValue(); - } + final ArgumentCaptor<ActivityManager.UidFrozenStateChangedCallback> frozenCaptor = + ArgumentCaptor.forClass(ActivityManager.UidFrozenStateChangedCallback.class); + verify(mActivityManager).registerUidFrozenStateChangedCallback( + any(HandlerExecutor.class), frozenCaptor.capture()); + mUidFrozenStateCallback = frozenCaptor.getValue(); // Unable to mock mMockContext to return a mock stats manager. // So just mocking the whole MetricsHelper instance. @@ -3744,79 +3739,11 @@ public final class AlarmManagerServiceTest { testTemporaryQuota_bumpedBeforeDeferral(STANDBY_BUCKET_RARE); } - @Test - public void exactListenerAlarmsRemovedOnCached() { - mockChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, true); - - setTestAlarmWithListener(ELAPSED_REALTIME, 31, getNewListener(() -> {}), WINDOW_EXACT, - TEST_CALLING_UID); - setTestAlarmWithListener(RTC, 42, getNewListener(() -> {}), 56, TEST_CALLING_UID); - setTestAlarm(ELAPSED_REALTIME, 54, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0, - TEST_CALLING_UID, null); - setTestAlarm(RTC, 49, 154, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null); - - setTestAlarmWithListener(ELAPSED_REALTIME, 21, getNewListener(() -> {}), WINDOW_EXACT, - TEST_CALLING_UID_2); - setTestAlarmWithListener(RTC, 412, getNewListener(() -> {}), 561, TEST_CALLING_UID_2); - setTestAlarm(ELAPSED_REALTIME, 26, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0, - TEST_CALLING_UID_2, null); - setTestAlarm(RTC, 549, 234, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID_2, null); - - assertEquals(8, mService.mAlarmStore.size()); - - mListener.handleUidCachedChanged(TEST_CALLING_UID, true); - assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); - assertEquals(7, mService.mAlarmStore.size()); - - mListener.handleUidCachedChanged(TEST_CALLING_UID_2, true); - assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); - assertEquals(6, mService.mAlarmStore.size()); - } - - @Test - public void alarmCountOnListenerCached() { - mockChangeEnabled(EXACT_LISTENER_ALARMS_DROPPED_ON_CACHED, true); - - // Set some alarms for TEST_CALLING_UID. - final int numExactListenerUid1 = 14; - for (int i = 0; i < numExactListenerUid1; i++) { - setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i, - getNewListener(() -> {})); - } - setTestAlarmWithListener(RTC, 42, getNewListener(() -> {}), 56, TEST_CALLING_UID); - setTestAlarm(ELAPSED_REALTIME, 54, getNewMockPendingIntent()); - setTestAlarm(RTC, 49, 154, getNewMockPendingIntent(), 0, 0, TEST_CALLING_UID, null); - - // Set some alarms for TEST_CALLING_UID_2. - final int numExactListenerUid2 = 9; - for (int i = 0; i < numExactListenerUid2; i++) { - setTestAlarmWithListener(ALARM_TYPES[i % 4], mNowElapsedTest + i, - getNewListener(() -> {}), WINDOW_EXACT, TEST_CALLING_UID_2); - } - setTestAlarmWithListener(RTC, 412, getNewListener(() -> {}), 561, TEST_CALLING_UID_2); - setTestAlarm(RTC_WAKEUP, 26, WINDOW_EXACT, getNewMockPendingIntent(), 0, 0, - TEST_CALLING_UID_2, null); - - assertEquals(numExactListenerUid1 + 3, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); - assertEquals(numExactListenerUid2 + 2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2)); - - mListener.handleUidCachedChanged(TEST_CALLING_UID, true); - assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); - assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); - assertEquals(numExactListenerUid2 + 2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2)); - - mListener.handleUidCachedChanged(TEST_CALLING_UID_2, true); - assertAndHandleMessageSync(REMOVE_EXACT_LISTENER_ALARMS_ON_CACHED); - assertEquals(3, mService.mAlarmsPerUid.get(TEST_CALLING_UID)); - assertEquals(2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2)); - } - private void executeUidFrozenStateCallback(int[] uids, int[] frozenStates) { assertNotNull(mUidFrozenStateCallback); mUidFrozenStateCallback.onUidFrozenStateChanged(uids, frozenStates); } - @EnableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS) @DisableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS) @Test public void exactListenerAlarmsRemovedOnFrozen() { @@ -3848,7 +3775,6 @@ public final class AlarmManagerServiceTest { assertEquals(6, mService.mAlarmStore.size()); } - @EnableFlags(Flags.FLAG_USE_FROZEN_STATE_TO_DROP_LISTENER_ALARMS) @DisableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS) @Test public void alarmCountOnListenerFrozen() { diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java index dcbc23410fdb..5a872ea04bcc 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java @@ -47,10 +47,8 @@ import static com.android.server.am.Flags.FLAG_AVOID_RESOLVING_TYPE; import static com.android.server.am.ProcessList.NETWORK_STATE_BLOCK; import static com.android.server.am.ProcessList.NETWORK_STATE_NO_CHANGE; import static com.android.server.am.ProcessList.NETWORK_STATE_UNBLOCK; - import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -80,6 +78,7 @@ import android.Manifest; import android.app.ActivityManager; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.ApplicationThreadConstants; import android.app.BackgroundStartPrivileges; import android.app.BroadcastOptions; import android.app.ForegroundServiceDelegationOptions; @@ -87,6 +86,7 @@ import android.app.IUidObserver; import android.app.Notification; import android.app.NotificationChannel; import android.app.SyncNotedAppOp; +import android.app.backup.BackupAnnotations; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -111,6 +111,7 @@ import android.os.Parcel; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; +import android.os.UserHandle; import android.permission.IPermissionManager; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; @@ -133,6 +134,7 @@ import com.android.server.am.ProcessList.IsolatedUidRange; import com.android.server.am.ProcessList.IsolatedUidRangeAllocator; import com.android.server.am.UidObserverController.ChangeRecord; import com.android.server.appop.AppOpsService; +import com.android.server.job.JobSchedulerInternal; import com.android.server.notification.NotificationManagerInternal; import com.android.server.wm.ActivityTaskManagerInternal; import com.android.server.wm.ActivityTaskManagerService; @@ -228,6 +230,7 @@ public class ActivityManagerServiceTest { @Mock private PackageManagerInternal mPackageManagerInternal; @Mock private ActivityTaskManagerInternal mActivityTaskManagerInternal; @Mock private NotificationManagerInternal mNotificationManagerInternal; + @Mock private JobSchedulerInternal mJobSchedulerInternal; @Mock private ContentResolver mContentResolver; private TestInjector mInjector; @@ -249,6 +252,7 @@ public class ActivityManagerServiceTest { LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); LocalServices.addService(ActivityTaskManagerInternal.class, mActivityTaskManagerInternal); LocalServices.addService(NotificationManagerInternal.class, mNotificationManagerInternal); + LocalServices.addService(JobSchedulerInternal.class, mJobSchedulerInternal); doReturn(new ComponentName("", "")).when(mPackageManagerInternal) .getSystemUiServiceComponent(); @@ -308,6 +312,7 @@ public class ActivityManagerServiceTest { LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); LocalServices.removeServiceForTest(NotificationManagerInternal.class); + LocalServices.removeServiceForTest(JobSchedulerInternal.class); if (mMockingSession != null) { mMockingSession.finishMocking(); @@ -1548,6 +1553,50 @@ public class ActivityManagerServiceTest { eq(notificationId), anyInt()); } + @SuppressWarnings("GuardedBy") + @Test + public void bindBackupAgent_fullBackup_shouldUseRestrictedMode_setsInFullBackup() + throws Exception { + ActivityManagerService spyAms = spy(mAms); + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.packageName = TEST_PACKAGE; + applicationInfo.processName = TEST_PACKAGE; + applicationInfo.uid = TEST_UID; + doReturn(applicationInfo).when(mPackageManager).getApplicationInfo(eq(TEST_PACKAGE), + anyLong(), anyInt()); + ProcessRecord appRec = new ProcessRecord(mAms, applicationInfo, TAG, TEST_UID); + doReturn(appRec).when(spyAms).getProcessRecordLocked(eq(TEST_PACKAGE), eq(TEST_UID)); + + spyAms.bindBackupAgent(TEST_PACKAGE, ApplicationThreadConstants.BACKUP_MODE_FULL, + UserHandle.USER_SYSTEM, + BackupAnnotations.BackupDestination.CLOUD, /* shouldUseRestrictedMode= */ + true); + + assertThat(appRec.isInFullBackup()).isTrue(); + } + + @SuppressWarnings("GuardedBy") + @Test + public void bindBackupAgent_fullBackup_shouldNotUseRestrictedMode_doesNotSetInFullBackup() + throws Exception { + ActivityManagerService spyAms = spy(mAms); + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.packageName = TEST_PACKAGE; + applicationInfo.processName = TEST_PACKAGE; + applicationInfo.uid = TEST_UID; + doReturn(applicationInfo).when(mPackageManager).getApplicationInfo(eq(TEST_PACKAGE), + anyLong(), anyInt()); + ProcessRecord appRec = new ProcessRecord(mAms, applicationInfo, TAG, TEST_UID); + doReturn(appRec).when(spyAms).getProcessRecordLocked(eq(TEST_PACKAGE), eq(TEST_UID)); + + spyAms.bindBackupAgent(TEST_PACKAGE, ApplicationThreadConstants.BACKUP_MODE_FULL, + UserHandle.USER_SYSTEM, + BackupAnnotations.BackupDestination.CLOUD, /* shouldUseRestrictedMode= */ + false); + + assertThat(appRec.isInFullBackup()).isFalse(); + } + private static class TestHandler extends Handler { private static final long WAIT_FOR_MSG_TIMEOUT_MS = 4000; // 4 sec private static final long WAIT_FOR_MSG_INTERVAL_MS = 400; // 0.4 sec diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java index a1a8b0ec7d2f..5eb23a24908d 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BaseBroadcastQueueTest.java @@ -58,6 +58,7 @@ import com.android.server.compat.PlatformCompat; import com.android.server.wm.ActivityTaskManagerService; import org.junit.Rule; +import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -185,10 +186,10 @@ public abstract class BaseBroadcastQueueTest { doReturn(mAppStartInfoTracker).when(mProcessList).getAppStartInfoTracker(); - doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt()); - doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), anyInt()); + doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), any(ApplicationInfo.class)); + doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), any(ApplicationInfo.class)); } public void tearDown() throws Exception { @@ -298,7 +299,7 @@ public abstract class BaseBroadcastQueueTest { filter.setPriority(priority); final BroadcastFilter res = new BroadcastFilter(filter, receiverList, receiverList.app.info.packageName, null, null, null, receiverList.uid, - receiverList.userId, false, false, true, + receiverList.userId, false, false, true, receiverList.app.info, mock(PlatformCompat.class)); receiverList.add(res); return res; @@ -308,4 +309,8 @@ public abstract class BaseBroadcastQueueTest { app.mOptRecord.setPendingFreeze(pendingFreeze); app.mOptRecord.setFrozen(frozen); } + + ArgumentMatcher<ApplicationInfo> appInfoEquals(int uid) { + return test -> (test.uid == uid); + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java index e977a7d46f30..5d106ace71dd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastFilterTest.java @@ -20,10 +20,13 @@ import static android.content.IntentFilter.SYSTEM_LOW_PRIORITY; import static com.google.common.truth.Truth.assertWithMessage; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import android.content.pm.ApplicationInfo; import android.os.Process; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; @@ -53,14 +56,14 @@ public class BroadcastFilterTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); + + doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), any(ApplicationInfo.class)); } @Test @EnableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES) public void testCalculateAdjustedPriority() { - doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt()); - { // Pairs of {initial-priority, expected-adjusted-priority} final Pair<Integer, Integer>[] priorities = new Pair[] { @@ -95,8 +98,8 @@ public class BroadcastFilterTest { @Test @EnableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES) public void testCalculateAdjustedPriority_withChangeIdDisabled() { - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt()); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), any(ApplicationInfo.class)); { // Pairs of {initial-priority, expected-adjusted-priority} @@ -132,9 +135,6 @@ public class BroadcastFilterTest { @Test @DisableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES) public void testCalculateAdjustedPriority_withFlagDisabled() { - doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt()); - { // Pairs of {initial-priority, expected-adjusted-priority} final Pair<Integer, Integer>[] priorities = new Pair[] { @@ -170,7 +170,7 @@ public class BroadcastFilterTest { @DisableFlags(Flags.FLAG_RESTRICT_PRIORITY_VALUES) public void testCalculateAdjustedPriority_withFlagDisabled_withChangeIdDisabled() { doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastFilter.CHANGE_RESTRICT_PRIORITY_VALUES), anyInt()); + eq(BroadcastFilter.RESTRICT_PRIORITY_VALUES), anyInt()); { // Pairs of {initial-priority, expected-adjusted-priority} @@ -215,6 +215,7 @@ public class BroadcastFilterTest { final String errorMsg = String.format("owner=%d; actualPriority=%d; expectedPriority=%d", owningUid, priority, expectedAdjustedPriority); assertWithMessage(errorMsg).that(BroadcastFilter.calculateAdjustedPriority( - owningUid, priority, mPlatformCompat)).isEqualTo(expectedAdjustedPriority); + owningUid, priority, mock(ApplicationInfo.class), mPlatformCompat)) + .isEqualTo(expectedAdjustedPriority); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index 1481085c5f71..82237bca2e34 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -47,6 +47,7 @@ import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doAnswer; @@ -184,7 +185,10 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest { } private static BroadcastFilter makeMockRegisteredReceiver() { - return mock(BroadcastFilter.class); + final BroadcastFilter filter = mock(BroadcastFilter.class); + final ApplicationInfo info = makeApplicationInfo(PACKAGE_ORANGE); + doReturn(info).when(filter).getApplicationInfo(); + return filter; } private BroadcastRecord makeBroadcastRecord(Intent intent) { @@ -716,9 +720,9 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest { @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE) @Test public void testRunnableAt_Cached_Prioritized_NonDeferrable_changeIdDisabled() { - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), - eq(getUidForPackage(PACKAGE_GREEN))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), + argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN)))); final List receivers = List.of( withPriority(makeManifestReceiver(PACKAGE_RED, PACKAGE_RED), 10), withPriority(makeManifestReceiver(PACKAGE_GREEN, PACKAGE_GREEN), -10)); @@ -1288,9 +1292,9 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest { @SuppressWarnings("GuardedBy") @Test public void testDeliveryGroupPolicy_prioritized_diffReceivers_changeIdDisabled() { - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), - eq(getUidForPackage(PACKAGE_GREEN))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), + argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN)))); final Intent screenOn = new Intent(Intent.ACTION_SCREEN_ON); final Intent screenOff = new Intent(Intent.ACTION_SCREEN_OFF); @@ -1823,9 +1827,9 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest { @SuppressWarnings("GuardedBy") @Test public void testDeliveryDeferredForCached_changeIdDisabled() throws Exception { - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), - eq(getUidForPackage(PACKAGE_GREEN))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), + argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN)))); final ProcessRecord greenProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_GREEN)); final ProcessRecord redProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_RED)); @@ -2027,9 +2031,9 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest { @Test public void testDeliveryDeferredForCached_withInfiniteDeferred_changeIdDisabled() throws Exception { - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), - eq(getUidForPackage(PACKAGE_GREEN))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), + argThat(appInfoEquals(getUidForPackage(PACKAGE_GREEN)))); final ProcessRecord greenProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_GREEN)); final ProcessRecord redProcess = makeProcessRecord(makeApplicationInfo(PACKAGE_RED)); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java index 9d92d5fe4f60..ea80f283793e 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java @@ -1659,8 +1659,9 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest { final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN); final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW); - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(receiverBlueApp.uid)); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), + argThat(appInfoEquals(receiverBlueApp.uid))); // Enqueue a normal broadcast that will go to several processes, and // then enqueue a foreground broadcast that risks reordering @@ -2471,8 +2472,9 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest { final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE); final ProcessRecord receiverGreenApp = makeActiveProcessRecord(PACKAGE_GREEN); - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(receiverBlueApp.uid)); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), + argThat(appInfoEquals(receiverBlueApp.uid))); mUidObserver.onUidStateChanged(receiverGreenApp.info.uid, ActivityManager.PROCESS_STATE_TOP, 0, ActivityManager.PROCESS_CAPABILITY_NONE); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java index a424bfdb8df4..8482fd609d05 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java @@ -19,12 +19,12 @@ package com.android.server.am; import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; -import static com.android.server.am.BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE; import static com.android.server.am.BroadcastRecord.DELIVERY_DEFERRED; import static com.android.server.am.BroadcastRecord.DELIVERY_DELIVERED; import static com.android.server.am.BroadcastRecord.DELIVERY_PENDING; import static com.android.server.am.BroadcastRecord.DELIVERY_SKIPPED; import static com.android.server.am.BroadcastRecord.DELIVERY_TIMEOUT; +import static com.android.server.am.BroadcastRecord.LIMIT_PRIORITY_SCOPE; import static com.android.server.am.BroadcastRecord.calculateBlockedUntilBeyondCount; import static com.android.server.am.BroadcastRecord.calculateDeferUntilActive; import static com.android.server.am.BroadcastRecord.calculateUrgent; @@ -35,7 +35,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import android.app.BackgroundStartPrivileges; @@ -63,6 +64,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnitRunner; @@ -108,8 +110,8 @@ public class BroadcastRecordTest { public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - doReturn(true).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), anyInt()); + doReturn(true).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), any(ApplicationInfo.class)); } @Test @@ -222,8 +224,8 @@ public class BroadcastRecordTest { @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE) @Test public void testIsPrioritized_withDifferentPriorities_withFirstUidChangeIdDisabled() { - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1)))); assertTrue(isPrioritized(List.of( createResolveInfo(PACKAGE1, getAppId(1), 10), @@ -256,8 +258,8 @@ public class BroadcastRecordTest { @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE) @Test public void testIsPrioritized_withDifferentPriorities_withLastUidChangeIdDisabled() { - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(3))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(3)))); assertTrue(isPrioritized(List.of( createResolveInfo(PACKAGE1, getAppId(1), 10), @@ -294,8 +296,8 @@ public class BroadcastRecordTest { @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE) @Test public void testIsPrioritized_withDifferentPriorities_withUidChangeIdDisabled() { - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(2))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(2)))); assertTrue(isPrioritized(List.of( createResolveInfo(PACKAGE1, getAppId(1), 10), @@ -328,10 +330,10 @@ public class BroadcastRecordTest { @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE) @Test public void testIsPrioritized_withDifferentPriorities_withMultipleUidChangeIdDisabled() { - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1))); - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(2))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1)))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(2)))); assertTrue(isPrioritized(List.of( createResolveInfo(PACKAGE1, getAppId(1), 10), @@ -362,10 +364,10 @@ public class BroadcastRecordTest { assertArrayEquals(new int[] {0, 0, 1, 1, 3}, calculateBlockedUntilBeyondCount(List.of( createResolveInfo(PACKAGE1, getAppId(1), 20), - createResolveInfo(PACKAGE2, getAppId(3), 20), + createResolveInfo(PACKAGE3, getAppId(3), 20), createResolveInfo(PACKAGE3, getAppId(3), 10), createResolveInfo(PACKAGE3, getAppId(3), 0), - createResolveInfo(PACKAGE3, getAppId(2), 0)), false, mPlatformCompat)); + createResolveInfo(PACKAGE2, getAppId(2), 0)), false, mPlatformCompat)); } @Test @@ -592,8 +594,8 @@ public class BroadcastRecordTest { @EnableFlags(Flags.FLAG_LIMIT_PRIORITY_SCOPE) @Test public void testSetDeliveryState_DeferUntilActive_changeIdDisabled() { - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1)))); final BroadcastRecord r = createBroadcastRecord( new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED), List.of( createResolveInfo(PACKAGE1, getAppId(1), 10), @@ -960,8 +962,8 @@ public class BroadcastRecordTest { createResolveInfo(PACKAGE2, getAppId(2)), createResolveInfo(PACKAGE3, getAppId(3))))); - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(1))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(1)))); assertArrayEquals(new boolean[] {false, true, true}, calculateChangeState( List.of(createResolveInfo(PACKAGE1, getAppId(1)), createResolveInfo(PACKAGE2, getAppId(2)), @@ -969,11 +971,11 @@ public class BroadcastRecordTest { assertArrayEquals(new boolean[] {false, true, false, true}, calculateChangeState( List.of(createResolveInfo(PACKAGE1, getAppId(1)), createResolveInfo(PACKAGE2, getAppId(2)), - createResolveInfo(PACKAGE2, getAppId(1)), + createResolveInfo(PACKAGE1, getAppId(1)), createResolveInfo(PACKAGE3, getAppId(3))))); - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(2))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(2)))); assertArrayEquals(new boolean[] {false, false, true}, calculateChangeState( List.of(createResolveInfo(PACKAGE1, getAppId(1)), createResolveInfo(PACKAGE2, getAppId(2)), @@ -987,8 +989,8 @@ public class BroadcastRecordTest { createResolveInfo(PACKAGE2, getAppId(2)), createResolveInfo(PACKAGE3, getAppId(3))))); - doReturn(false).when(mPlatformCompat).isChangeEnabledByUidInternalNoLogging( - eq(BroadcastRecord.CHANGE_LIMIT_PRIORITY_SCOPE), eq(getAppId(3))); + doReturn(false).when(mPlatformCompat).isChangeEnabledInternalNoLogging( + eq(BroadcastRecord.LIMIT_PRIORITY_SCOPE), argThat(appInfoEquals(getAppId(3)))); assertArrayEquals(new boolean[] {false, false, false}, calculateChangeState( List.of(createResolveInfo(PACKAGE1, getAppId(1)), createResolveInfo(PACKAGE2, getAppId(2)), @@ -998,14 +1000,14 @@ public class BroadcastRecordTest { List.of(createResolveInfo(PACKAGE1, getAppId(1)), createResolveInfo(PACKAGE3, getAppId(3)), createResolveInfo(PACKAGE2, getAppId(2)), - createResolveInfo(PACKAGE2, getAppId(1)), + createResolveInfo(PACKAGE1, getAppId(1)), createResolveInfo(PACKAGE2, getAppId(2)), createResolveInfo(PACKAGE3, getAppId(3))))); } private boolean[] calculateChangeState(List<Object> receivers) { return BroadcastRecord.calculateChangeStateForReceivers(receivers, - CHANGE_LIMIT_PRIORITY_SCOPE, mPlatformCompat); + LIMIT_PRIORITY_SCOPE, mPlatformCompat); } private static void cleanupDisabledPackageReceivers(BroadcastRecord record, @@ -1185,4 +1187,8 @@ public class BroadcastRecordTest { assertEquals("deferred", expectedDeferredCount, r.deferredCount); assertEquals("beyond", expectedBeyondCount, r.beyondCount); } + + private ArgumentMatcher<ApplicationInfo> appInfoEquals(int uid) { + return test -> (test.uid == uid); + } } 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 f82a86092064..a9569b4096ff 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -1427,6 +1427,31 @@ public class MockingOomAdjusterTests { @SuppressWarnings("GuardedBy") @Test + public void testUpdateOomAdj_DoOne_Service_NotPerceptible_AboveClient() { + ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, + MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); + ProcessRecord client = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID, + MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false)); + ProcessRecord service = spy(makeDefaultProcessRecord(MOCKAPP3_PID, MOCKAPP3_UID, + MOCKAPP3_PROCESSNAME, MOCKAPP3_PACKAGENAME, false)); + bindService(app, client, null, null, Context.BIND_NOT_PERCEPTIBLE, mock(IBinder.class)); + bindService(service, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class)); + mProcessStateController.setRunningRemoteAnimation(client, true); + mProcessStateController.updateHasAboveClientLocked(app.mServices); + setWakefulness(PowerManagerInternal.WAKEFULNESS_AWAKE); + updateOomAdj(client, app, service); + + final int expectedAdj; + if (Flags.addModifyRawOomAdjServiceLevel()) { + expectedAdj = SERVICE_ADJ; + } else { + expectedAdj = CACHED_APP_MIN_ADJ; + } + assertEquals(expectedAdj, app.mState.getSetAdj()); + } + + @SuppressWarnings("GuardedBy") + @Test public void testUpdateOomAdj_DoOne_Service_NotVisible() { ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID, MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, false)); @@ -2906,7 +2931,7 @@ public class MockingOomAdjusterTests { // Simulate binding to a service in the same process using BIND_ABOVE_CLIENT and // verify that its OOM adjustment level is unaffected. bindService(service, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class)); - app.mServices.updateHasAboveClientLocked(); + mProcessStateController.updateHasAboveClientLocked(app.mServices); assertTrue(app.mServices.hasAboveClient()); updateOomAdj(app); @@ -2928,7 +2953,7 @@ public class MockingOomAdjusterTests { // Simulate binding to a service in the same process using BIND_ABOVE_CLIENT and // verify that its OOM adjustment level is unaffected. bindService(app, app, null, null, Context.BIND_ABOVE_CLIENT, mock(IBinder.class)); - app.mServices.updateHasAboveClientLocked(); + mProcessStateController.updateHasAboveClientLocked(app.mServices); assertFalse(app.mServices.hasAboveClient()); updateOomAdj(app); @@ -2983,7 +3008,7 @@ public class MockingOomAdjusterTests { // Since sr.app is null, this service cannot be in the same process as the // client so we expect the BIND_ABOVE_CLIENT adjustment to take effect. - app.mServices.updateHasAboveClientLocked(); + mProcessStateController.updateHasAboveClientLocked(app.mServices); updateOomAdj(app); assertTrue(app.mServices.hasAboveClient()); assertNotEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj()); @@ -3306,7 +3331,7 @@ public class MockingOomAdjusterTests { if (Flags.pushGlobalStateToOomadjuster()) { mProcessStateController.setBackupTarget(app, app.userId); } else { - BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0); + BackupRecord backupTarget = new BackupRecord(null, 0, 0, 0, true); backupTarget.app = app; doReturn(backupTarget).when(mService.mBackupTargets).get(anyInt()); } diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java index 65286d9aabc7..07f2188d30eb 100644 --- a/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java @@ -18,9 +18,7 @@ package com.android.server.backup; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; - import static com.google.common.truth.Truth.assertThat; - import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -32,20 +30,27 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.when; import android.annotation.UserIdInt; +import android.app.ActivityManagerInternal; +import android.app.ApplicationThreadConstants; +import android.app.IActivityManager; import android.app.backup.BackupAgent; -import android.app.backup.BackupAnnotations; import android.app.backup.BackupAnnotations.BackupDestination; +import android.app.backup.BackupAnnotations.OperationType; import android.app.backup.BackupRestoreEventLogger.DataTypeResult; import android.app.backup.IBackupManagerMonitor; import android.app.backup.IBackupObserver; import android.app.job.JobInfo; import android.app.job.JobScheduler; +import android.compat.testing.PlatformCompatChangeRule; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Handler; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.testing.TestableContext; import android.util.FeatureFlagUtils; @@ -68,7 +73,9 @@ import com.google.common.collect.ImmutableSet; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TestRule; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -77,8 +84,12 @@ import org.mockito.quality.Strictness; import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.function.IntConsumer; +import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; +import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; + @Presubmit @RunWith(AndroidJUnit4.class) public class UserBackupManagerServiceTest { @@ -88,6 +99,11 @@ public class UserBackupManagerServiceTest { private static final int WORKER_THREAD_TIMEOUT_MILLISECONDS = 100; @UserIdInt private static final int USER_ID = 0; + @Rule + public TestRule compatChangeRule = new PlatformCompatChangeRule(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Mock IBackupManagerMonitor mBackupManagerMonitor; @Mock IBackupObserver mBackupObserver; @Mock PackageManager mPackageManager; @@ -99,10 +115,14 @@ public class UserBackupManagerServiceTest { @Mock JobScheduler mJobScheduler; @Mock BackupHandler mBackupHandler; @Mock BackupManagerMonitorEventSender mBackupManagerMonitorEventSender; + @Mock IActivityManager mActivityManager; + @Mock + ActivityManagerInternal mActivityManagerInternal; private TestableContext mContext; private MockitoSession mSession; private TestBackupService mService; + private ApplicationInfo mTestPackageApplicationInfo; @Before public void setUp() throws Exception { @@ -120,12 +140,14 @@ public class UserBackupManagerServiceTest { mContext.getTestablePermissions().setPermission(android.Manifest.permission.BACKUP, PackageManager.PERMISSION_GRANTED); - mService = new TestBackupService(mContext, mPackageManager, mOperationStorage, - mTransportManager, mBackupHandler); + mService = new TestBackupService(); mService.setEnabled(true); mService.setSetupComplete(true); mService.enqueueFullBackup("com.test.backup.app", /* lastBackedUp= */ 0); - } + + mTestPackageApplicationInfo = new ApplicationInfo(); + mTestPackageApplicationInfo.packageName = TEST_PACKAGE; + } @After public void tearDown() { @@ -298,9 +320,160 @@ public class UserBackupManagerServiceTest { new DataTypeResult(/* dataType */ "type_2")); mService.reportDelayedRestoreResult(TEST_PACKAGE, results); - verify(mBackupManagerMonitorEventSender).sendAgentLoggingResults( - eq(packageInfo), eq(results), eq(BackupAnnotations.OperationType.RESTORE)); + eq(packageInfo), eq(results), eq(OperationType.RESTORE)); + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + public void bindToAgentSynchronous_restrictedModeChangesFlagOff_shouldUseRestrictedMode() + throws Exception { + mService.bindToAgentSynchronous(mTestPackageApplicationInfo, + ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); + + verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), + /* useRestrictedMode= */ eq(true)); + // Make sure we never hit the code that checks the property. + verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt()); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + public void bindToAgentSynchronous_keyValueBackup_shouldNotUseRestrictedMode() + throws Exception { + mService.bindToAgentSynchronous(mTestPackageApplicationInfo, + ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL, BackupDestination.CLOUD); + + verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), + /* useRestrictedMode= */ eq(false)); + // Make sure we never hit the code that checks the property. + verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt()); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + public void bindToAgentSynchronous_keyValueRestore_shouldNotUseRestrictedMode() + throws Exception { + mService.bindToAgentSynchronous(mTestPackageApplicationInfo, + ApplicationThreadConstants.BACKUP_MODE_RESTORE, BackupDestination.CLOUD); + + verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), + /* useRestrictedMode= */ eq(false)); + // Make sure we never hit the code that checks the property. + verify(mPackageManager, never()).getPropertyAsUser(any(), any(), any(), anyInt()); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + public void bindToAgentSynchronous_packageOptedIn_shouldUseRestrictedMode() + throws Exception { + when(mPackageManager.getPropertyAsUser( + eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), + eq(TEST_PACKAGE), any(), anyInt())).thenReturn(new PackageManager.Property( + PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, /* value= */ true, + TEST_PACKAGE, /* className= */ null)); + + mService.bindToAgentSynchronous(mTestPackageApplicationInfo, + ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); + + verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), + /* useRestrictedMode= */ eq(true)); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + public void bindToAgentSynchronous_packageOptedOut_shouldNotUseRestrictedMode() + throws Exception { + when(mPackageManager.getPropertyAsUser( + eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), + eq(TEST_PACKAGE), any(), anyInt())).thenReturn(new PackageManager.Property( + PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE, /* value= */ false, + TEST_PACKAGE, /* className= */ null)); + + mService.bindToAgentSynchronous(mTestPackageApplicationInfo, + ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); + + verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), + /* useRestrictedMode= */ eq(false)); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + @DisableCompatChanges({UserBackupManagerService.OS_DECIDES_BACKUP_RESTRICTED_MODE}) + public void bindToAgentSynchronous_targetSdkBelowB_shouldUseRestrictedMode() + throws Exception { + // Mock that the app has not explicitly set the property. + when(mPackageManager.getPropertyAsUser( + eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), + eq(TEST_PACKAGE), any(), anyInt())).thenThrow( + new PackageManager.NameNotFoundException() + ); + + mService.bindToAgentSynchronous(mTestPackageApplicationInfo, + ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); + + verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), + /* useRestrictedMode= */ eq(true)); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + @EnableCompatChanges({UserBackupManagerService.OS_DECIDES_BACKUP_RESTRICTED_MODE}) + public void bindToAgentSynchronous_targetSdkB_notInList_shouldUseRestrictedMode() + throws Exception { + // Mock that the app has not explicitly set the property. + when(mPackageManager.getPropertyAsUser( + eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), + eq(TEST_PACKAGE), any(), anyInt())).thenThrow( + new PackageManager.NameNotFoundException() + ); + mService.clearNoRestrictedModePackages(); + + mService.bindToAgentSynchronous(mTestPackageApplicationInfo, + ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); + + verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), + /* useRestrictedMode= */ eq(true)); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + @EnableCompatChanges({UserBackupManagerService.OS_DECIDES_BACKUP_RESTRICTED_MODE}) + public void bindToAgentSynchronous_forRestore_targetSdkB_inList_shouldNotUseRestrictedMode() + throws Exception { + // Mock that the app has not explicitly set the property. + when(mPackageManager.getPropertyAsUser( + eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), + eq(TEST_PACKAGE), any(), anyInt())).thenThrow( + new PackageManager.NameNotFoundException() + ); + mService.setNoRestrictedModePackages(Set.of(TEST_PACKAGE), OperationType.RESTORE); + + mService.bindToAgentSynchronous(mTestPackageApplicationInfo, + ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL, BackupDestination.CLOUD); + + verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), + /* useRestrictedMode= */ eq(false)); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_RESTRICTED_MODE_CHANGES) + @EnableCompatChanges({UserBackupManagerService.OS_DECIDES_BACKUP_RESTRICTED_MODE}) + public void bindToAgentSynchronous_forBackup_targetSdkB_inList_shouldNotUseRestrictedMode() + throws Exception { + // Mock that the app has not explicitly set the property. + when(mPackageManager.getPropertyAsUser( + eq(PackageManager.PROPERTY_USE_RESTRICTED_BACKUP_MODE), + eq(TEST_PACKAGE), any(), anyInt())).thenThrow( + new PackageManager.NameNotFoundException() + ); + mService.setNoRestrictedModePackages(Set.of(TEST_PACKAGE), OperationType.BACKUP); + + mService.bindToAgentSynchronous(mTestPackageApplicationInfo, + ApplicationThreadConstants.BACKUP_MODE_FULL, BackupDestination.CLOUD); + + verify(mActivityManager).bindBackupAgent(eq(TEST_PACKAGE), anyInt(), anyInt(), anyInt(), + /* useRestrictedMode= */ eq(false)); } private static PackageInfo getPackageInfo(String packageName) { @@ -316,11 +489,9 @@ public class UserBackupManagerServiceTest { private volatile Thread mWorkerThread = null; - TestBackupService(Context context, PackageManager packageManager, - LifecycleOperationStorage operationStorage, TransportManager transportManager, - BackupHandler backupHandler) { - super(context, packageManager, operationStorage, transportManager, backupHandler, - createConstants(context)); + TestBackupService() { + super(mContext, mPackageManager, mOperationStorage, mTransportManager, mBackupHandler, + createConstants(mContext), mActivityManager, mActivityManagerInternal); } private static BackupManagerConstants createConstants(Context context) { diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java index 94742537ed1a..331057398949 100644 --- a/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/backup/fullbackup/PerformFullTransportBackupTaskTest.java @@ -18,34 +18,95 @@ package com.android.server.backup.fullbackup; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.when; +import android.app.backup.BackupAnnotations; +import android.app.backup.BackupTransport; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.platform.test.annotations.Presubmit; import androidx.test.runner.AndroidJUnit4; +import com.android.server.backup.BackupAgentTimeoutParameters; +import com.android.server.backup.OperationStorage; import com.android.server.backup.TransportManager; import com.android.server.backup.UserBackupManagerService; +import com.android.server.backup.transport.BackupTransportClient; +import com.android.server.backup.transport.TransportConnection; +import com.android.server.backup.utils.BackupEligibilityRules; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + @Presubmit @RunWith(AndroidJUnit4.class) public class PerformFullTransportBackupTaskTest { + private static final String TEST_PACKAGE_1 = "package1"; + private static final String TEST_PACKAGE_2 = "package2"; + + @Mock + BackupAgentTimeoutParameters mBackupAgentTimeoutParameters; + @Mock + BackupEligibilityRules mBackupEligibilityRules; @Mock UserBackupManagerService mBackupManagerService; @Mock + BackupTransportClient mBackupTransportClient; + @Mock + CountDownLatch mLatch; + @Mock + OperationStorage mOperationStorage; + @Mock + PackageManager mPackageManager; + @Mock + TransportConnection mTransportConnection; + @Mock TransportManager mTransportManager; + @Mock + UserBackupManagerService.BackupWakeLock mWakeLock; + + private final List<String> mEligiblePackages = new ArrayList<>(); + + private PerformFullTransportBackupTask mTask; @Before - public void setUp() { + public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + when(mBackupManagerService.getPackageManager()).thenReturn(mPackageManager); + when(mBackupManagerService.getQueueLock()).thenReturn("something!"); + when(mBackupManagerService.isEnabled()).thenReturn(true); + when(mBackupManagerService.getWakelock()).thenReturn(mWakeLock); + when(mBackupManagerService.isSetupComplete()).thenReturn(true); + when(mBackupManagerService.getAgentTimeoutParameters()).thenReturn( + mBackupAgentTimeoutParameters); when(mBackupManagerService.getTransportManager()).thenReturn(mTransportManager); + when(mTransportManager.getCurrentTransportClient(any())).thenReturn(mTransportConnection); + when(mTransportConnection.connectOrThrow(any())).thenReturn(mBackupTransportClient); + when(mTransportConnection.connect(any())).thenReturn(mBackupTransportClient); + when(mBackupTransportClient.performFullBackup(any(), any(), anyInt())).thenReturn( + BackupTransport.TRANSPORT_ERROR); + when(mBackupEligibilityRules.appIsEligibleForBackup( + argThat(app -> mEligiblePackages.contains(app.packageName)))).thenReturn( + true); + when(mBackupEligibilityRules.appGetsFullBackup( + argThat(app -> mEligiblePackages.contains(app.packageName)))).thenReturn( + true); } @Test @@ -70,4 +131,49 @@ public class PerformFullTransportBackupTaskTest { /* backupEligibilityRules */ null); }); } + + @Test + public void run_setsAndClearsNoRestrictedModePackages() throws Exception { + mockPackageEligibleForFullBackup(TEST_PACKAGE_1); + mockPackageEligibleForFullBackup(TEST_PACKAGE_2); + createTask(new String[] {TEST_PACKAGE_1, TEST_PACKAGE_2}); + when(mBackupTransportClient.getPackagesThatShouldNotUseRestrictedMode(any(), + anyInt())).thenReturn(Set.of("package1")); + + mTask.run(); + + InOrder inOrder = inOrder(mBackupManagerService); + inOrder.verify(mBackupManagerService).setNoRestrictedModePackages( + eq(Set.of("package1")), + eq(BackupAnnotations.OperationType.BACKUP)); + inOrder.verify(mBackupManagerService).clearNoRestrictedModePackages(); + } + + private void createTask(String[] packageNames) { + mTask = PerformFullTransportBackupTask + .newWithCurrentTransport( + mBackupManagerService, + mOperationStorage, + /* observer */ null, + /* whichPackages */ packageNames, + /* updateSchedule */ false, + /* runningJob */ null, + mLatch, + /* backupObserver */ null, + /* monitor */ null, + /* userInitiated */ false, + /* caller */ null, + mBackupEligibilityRules); + } + + private void mockPackageEligibleForFullBackup(String packageName) throws Exception { + mEligiblePackages.add(packageName); + ApplicationInfo appInfo = new ApplicationInfo(); + appInfo.packageName = packageName; + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = packageName; + packageInfo.applicationInfo = appInfo; + when(mPackageManager.getPackageInfoAsUser(eq(packageName), anyInt(), anyInt())).thenReturn( + packageInfo); + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java index 414532b88e22..055adf68ee0f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/backup/restore/PerformUnifiedRestoreTaskTest.java @@ -23,8 +23,10 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.backup.BackupAnnotations; import android.app.backup.BackupDataInput; import android.app.backup.BackupDataOutput; import android.app.backup.BackupTransport; @@ -91,6 +93,8 @@ public class PerformUnifiedRestoreTaskTest { private UserBackupManagerService mBackupManagerService; @Mock private TransportConnection mTransportConnection; + @Mock + private BackupTransportClient mBackupTransportClient; private Set<String> mExcludedkeys = new HashSet<>(); private Map<String, String> mBackupData = new HashMap<>(); @@ -151,6 +155,23 @@ public class PerformUnifiedRestoreTaskTest { } @Test + public void setNoRestrictedModePackages_callsTransportAndSetsValue() throws Exception { + PackageInfo packageInfo1 = new PackageInfo(); + packageInfo1.packageName = "package1"; + PackageInfo packageInfo2 = new PackageInfo(); + packageInfo2.packageName = "package2"; + when(mBackupTransportClient.getPackagesThatShouldNotUseRestrictedMode(any(), + anyInt())).thenReturn(Set.of("package1")); + + mRestoreTask.setNoRestrictedModePackages(mBackupTransportClient, + new PackageInfo[]{packageInfo1, packageInfo2}); + + verify(mBackupManagerService).setNoRestrictedModePackages( + eq(Set.of("package1")), + eq(BackupAnnotations.OperationType.RESTORE)); + } + + @Test public void testFilterExcludedKeys() throws Exception { when(mBackupManagerService.getExcludedRestoreKeys(eq(PACKAGE_NAME))) .thenReturn(mExcludedkeys); diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java index 2d7d46f83c47..13e32078f609 100644 --- a/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/backup/transport/BackupTransportClientTest.java @@ -19,7 +19,14 @@ package com.android.server.backup.transport; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; - +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.verify; + +import android.app.backup.BackupAnnotations.OperationType; import android.app.backup.BackupTransport; import android.app.backup.IBackupManagerMonitor; import android.app.backup.RestoreDescription; @@ -38,15 +45,31 @@ import com.android.internal.backup.IBackupTransport; import com.android.internal.backup.ITransportStatusCallback; import com.android.internal.infra.AndroidFuture; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.util.List; +import java.util.Set; @Presubmit @RunWith(AndroidJUnit4.class) public class BackupTransportClientTest { + @Mock + IBackupTransport mMockBackupTransport; + + private BackupTransportClient mMockingTransportClient; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mMockingTransportClient = new BackupTransportClient( + mMockBackupTransport); + } + private static class TestFuturesFakeTransportBinder extends FakeTransportBinderBase { public final Object mLock = new Object(); @@ -128,6 +151,70 @@ public class BackupTransportClientTest { thread.join(); } + @Test + public void getPackagesThatShouldNotUseRestrictedMode_passesSetAsListToBinder() + throws Exception { + mockGetPackagesThatShouldNotUseRestrictedModeReturn(List.of("package1", "package2")); + + mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode( + Set.of("package1", "package2"), + OperationType.BACKUP); + + verify(mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode( + argThat(list -> Set.copyOf(list).equals(Set.of("package1", "package2"))), + eq(OperationType.BACKUP), any()); + } + + @Test + public void getPackagesThatShouldNotUseRestrictedMode_forRestore_callsBinderForRestore() + throws Exception { + mockGetPackagesThatShouldNotUseRestrictedModeReturn(null); + + mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode( + Set.of(), + OperationType.RESTORE); + + verify(mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(any(), + eq(OperationType.RESTORE), any()); + } + + @Test + public void getPackagesThatShouldNotUseRestrictedMode_forBackup_callsBinderForBackup() + throws Exception { + mockGetPackagesThatShouldNotUseRestrictedModeReturn(null); + + mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode( + Set.of(), + OperationType.BACKUP); + + verify(mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(any(), + eq(OperationType.BACKUP), any()); + } + + @Test + public void getPackagesThatShouldNotUseRestrictedMode_nullResult_returnsEmptySet() + throws Exception { + mockGetPackagesThatShouldNotUseRestrictedModeReturn(null); + + Set<String> result = mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode( + Set.of(), + OperationType.BACKUP); + + assertThat(result).isEqualTo(Set.of()); + } + + @Test + public void getPackagesThatShouldNotUseRestrictedMode_returnsResultAsSet() + throws Exception { + mockGetPackagesThatShouldNotUseRestrictedModeReturn(List.of("package1", "package2")); + + Set<String> result = mMockingTransportClient.getPackagesThatShouldNotUseRestrictedMode( + Set.of("package1", "package2"), + OperationType.BACKUP); + + assertThat(result).isEqualTo(Set.of("package1", "package2")); + } + private static class TestCallbacksFakeTransportBinder extends FakeTransportBinderBase { public final Object mLock = new Object(); @@ -158,7 +245,6 @@ public class BackupTransportClientTest { assertThat(status).isEqualTo(123); } - @Test public void testFinishBackup_completesLater_returnsStatus() throws Exception { TestCallbacksFakeTransportBinder binder = new TestCallbacksFakeTransportBinder(); @@ -211,6 +297,14 @@ public class BackupTransportClientTest { thread.join(); } + private void mockGetPackagesThatShouldNotUseRestrictedModeReturn(List<String> returnList) + throws Exception { + doAnswer( + i -> ((AndroidFuture<List<String>>) i.getArguments()[2]).complete(returnList)).when( + mMockBackupTransport).getPackagesThatShouldNotUseRestrictedMode(any(), anyInt(), + any()); + } + // Convenience layer so we only need to fake specific methods useful for each test case. private static class FakeTransportBinderBase implements IBackupTransport { @Override public void name(AndroidFuture<String> f) throws RemoteException {} @@ -258,6 +352,10 @@ public class BackupTransportClientTest { @Override public void getBackupManagerMonitor(AndroidFuture<IBackupManagerMonitor> resultFuture) throws RemoteException {} + @Override + public void getPackagesThatShouldNotUseRestrictedMode(List<String> packageNames, + int operationType, AndroidFuture<List<String>> resultFuture) + throws RemoteException {} @Override public IBinder asBinder() { return null; } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java index f6c644e3d4d4..20ac0781e2ed 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/InstallDependencyHelperTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import android.content.Context; import android.content.pm.SharedLibraryInfo; import android.content.pm.parsing.ApkLite; import android.content.pm.parsing.ApkLiteParseUtils; @@ -34,6 +35,8 @@ import android.content.pm.parsing.PackageLite; import android.content.pm.parsing.result.ParseResult; import android.content.pm.parsing.result.ParseTypeImpl; import android.os.FileUtils; +import android.os.Handler; +import android.os.Looper; import android.os.OutcomeReceiver; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; @@ -71,13 +74,17 @@ public class InstallDependencyHelperTest { private static final String PUSH_FILE_DIR = "/data/local/tmp/tests/smockingservicestest/pm/"; private static final String TEST_APP_USING_SDK1_AND_SDK2 = "HelloWorldUsingSdk1And2.apk"; + private final Handler mHandler = new Handler(Looper.getMainLooper()); + @Mock private SharedLibrariesImpl mSharedLibraries; + @Mock private Context mContext; + @Mock private Computer mComputer; private InstallDependencyHelper mInstallDependencyHelper; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mInstallDependencyHelper = new InstallDependencyHelper(mSharedLibraries); + mInstallDependencyHelper = new InstallDependencyHelper(mContext, mSharedLibraries); } @Test @@ -88,7 +95,8 @@ public class InstallDependencyHelperTest { PackageLite pkg = getPackageLite(TEST_APP_USING_SDK1_AND_SDK2); CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ false); - mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, callback); + mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer, + 0, mHandler, callback); callback.assertFailure(); assertThat(callback.error).hasMessageThat().contains("xyz"); @@ -104,11 +112,12 @@ public class InstallDependencyHelperTest { .thenReturn(missingDependency); CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ false); - mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, callback); + mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer, + 0, mHandler, callback); callback.assertFailure(); assertThat(callback.error).hasMessageThat().contains( - "Failed to bind to Dependency Installer"); + "Dependency Installer Service not found"); } @@ -121,7 +130,8 @@ public class InstallDependencyHelperTest { .thenReturn(missingDependency); CallbackHelper callback = new CallbackHelper(/*expectSuccess=*/ true); - mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, callback); + mInstallDependencyHelper.resolveLibraryDependenciesIfNeeded(pkg, mComputer, + 0, mHandler, callback); callback.assertSuccess(); } diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java index 58489f398775..0881b4cf9bcf 100644 --- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java +++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java @@ -18,6 +18,7 @@ package com.android.server.power.hint; import static com.android.server.power.hint.HintManagerService.CLEAN_UP_UID_DELAY_MILLIS; +import static com.android.server.power.hint.HintManagerService.DEFAULT_HEADROOM_PID; import static com.google.common.truth.Truth.assertThat; @@ -51,11 +52,15 @@ import android.content.pm.PackageManager; import android.hardware.common.fmq.MQDescriptor; import android.hardware.power.ChannelConfig; import android.hardware.power.ChannelMessage; +import android.hardware.power.CpuHeadroomParams; +import android.hardware.power.GpuHeadroomParams; import android.hardware.power.IPower; import android.hardware.power.SessionConfig; import android.hardware.power.SessionTag; import android.hardware.power.WorkDuration; import android.os.Binder; +import android.os.CpuHeadroomParamsInternal; +import android.os.GpuHeadroomParamsInternal; import android.os.IBinder; import android.os.IHintSession; import android.os.PerformanceHintManager; @@ -128,11 +133,11 @@ public class HintManagerServiceTest { private static final long[] TIMESTAMPS_ZERO = new long[] {}; private static final long[] TIMESTAMPS_TWO = new long[] {1L, 2L}; private static final WorkDuration[] WORK_DURATIONS_FIVE = new WorkDuration[] { - makeWorkDuration(1L, 11L, 1L, 8L, 4L), - makeWorkDuration(2L, 13L, 2L, 8L, 6L), - makeWorkDuration(3L, 333333333L, 3L, 8L, 333333333L), - makeWorkDuration(2L, 13L, 2L, 0L, 6L), - makeWorkDuration(2L, 13L, 2L, 8L, 0L), + makeWorkDuration(1L, 11L, 1L, 8L, 4L), + makeWorkDuration(2L, 13L, 2L, 8L, 6L), + makeWorkDuration(3L, 333333333L, 3L, 8L, 333333333L), + makeWorkDuration(2L, 13L, 2L, 0L, 6L), + makeWorkDuration(2L, 13L, 2L, 8L, 0L), }; private static final String TEST_APP_NAME = "com.android.test.app"; @@ -187,17 +192,17 @@ public class HintManagerServiceTest { when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID), eq(SESSION_TIDS_A), eq(DEFAULT_TARGET_DURATION), anyInt(), any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[0], - SESSION_IDS[0])); + SESSION_IDS[0])); when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID), eq(SESSION_TIDS_B), eq(DOUBLED_TARGET_DURATION), anyInt(), any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[1], - SESSION_IDS[1])); + SESSION_IDS[1])); when(mNativeWrapperMock.halCreateHintSessionWithConfig(eq(TGID), eq(UID), eq(SESSION_TIDS_C), eq(0L), anyInt(), any(SessionConfig.class))).thenAnswer(fakeCreateWithConfig(SESSION_PTRS[2], - SESSION_IDS[2])); + SESSION_IDS[2])); - when(mIPowerMock.getInterfaceVersion()).thenReturn(5); + when(mIPowerMock.getInterfaceVersion()).thenReturn(6); when(mIPowerMock.getSessionChannel(anyInt(), anyInt())).thenReturn(mConfig); LocalServices.removeServiceForTest(ActivityManagerInternal.class); LocalServices.addService(ActivityManagerInternal.class, mAmInternalMock); @@ -217,8 +222,8 @@ public class HintManagerServiceTest { when(mNativeWrapperMock.halCreateHintSession(eq(TGID), eq(UID), eq(SESSION_TIDS_C), eq(0L))).thenReturn(SESSION_PTRS[2]); when(mNativeWrapperMock.halCreateHintSessionWithConfig(anyInt(), anyInt(), - any(int[].class), anyLong(), anyInt(), - any(SessionConfig.class))).thenThrow(new UnsupportedOperationException()); + any(int[].class), anyLong(), anyInt(), + any(SessionConfig.class))).thenThrow(new UnsupportedOperationException()); } static class NativeWrapperFake extends NativeWrapper { @@ -337,7 +342,7 @@ public class HintManagerServiceTest { SESSION_TIDS_C, 0L, SessionTag.OTHER, new SessionConfig()); assertNotNull(c); verify(mNativeWrapperMock, times(3)).halCreateHintSession(anyInt(), anyInt(), - any(int[].class), anyLong()); + any(int[].class), anyLong()); } @Test @@ -487,7 +492,7 @@ public class HintManagerServiceTest { AppHintSession a = (AppHintSession) service.getBinderServiceInstance() .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION, - SessionTag.OTHER, new SessionConfig()); + SessionTag.OTHER, new SessionConfig()); a.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET); verify(mNativeWrapperMock, times(1)).halSendHint(anyLong(), @@ -514,7 +519,7 @@ public class HintManagerServiceTest { AppHintSession a = (AppHintSession) service.getBinderServiceInstance() .createHintSessionWithConfig(token, SESSION_TIDS_A, DEFAULT_TARGET_DURATION, - SessionTag.OTHER, new SessionConfig()); + SessionTag.OTHER, new SessionConfig()); service.mUidObserver.onUidStateChanged( a.mUid, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0); @@ -1096,4 +1101,157 @@ public class HintManagerServiceTest { verify(mIPowerMock, times(1)).getSessionChannel(eq(TGID), eq(UID)); assertTrue(service.hasChannel(TGID, UID)); } + + @Test + public void testHeadroomPowerHalNotSupported() throws Exception { + when(mIPowerMock.getInterfaceVersion()).thenReturn(5); + HintManagerService service = createService(); + assertThrows(UnsupportedOperationException.class, () -> { + service.getBinderServiceInstance().getCpuHeadroom(null); + }); + assertThrows(UnsupportedOperationException.class, () -> { + service.getBinderServiceInstance().getGpuHeadroom(null); + }); + assertThrows(UnsupportedOperationException.class, () -> { + service.getBinderServiceInstance().getCpuHeadroomMinIntervalMillis(); + }); + assertThrows(UnsupportedOperationException.class, () -> { + service.getBinderServiceInstance().getGpuHeadroomMinIntervalMillis(); + }); + } + + @Test + public void testCpuHeadroomCache() throws Exception { + when(mIPowerMock.getCpuHeadroomMinIntervalMillis()).thenReturn(2000L); + CpuHeadroomParamsInternal params1 = new CpuHeadroomParamsInternal(); + CpuHeadroomParams halParams1 = new CpuHeadroomParams(); + halParams1.calculationType = CpuHeadroomParams.CalculationType.MIN; + halParams1.selectionType = CpuHeadroomParams.SelectionType.ALL; + halParams1.pid = Process.myPid(); + + CpuHeadroomParamsInternal params2 = new CpuHeadroomParamsInternal(); + params2.usesDeviceHeadroom = true; + params2.calculationType = CpuHeadroomParams.CalculationType.AVERAGE; + params2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE; + CpuHeadroomParams halParams2 = new CpuHeadroomParams(); + halParams2.calculationType = CpuHeadroomParams.CalculationType.AVERAGE; + halParams2.selectionType = CpuHeadroomParams.SelectionType.PER_CORE; + halParams2.pid = DEFAULT_HEADROOM_PID; + + float[] headroom1 = new float[] {0.1f}; + when(mIPowerMock.getCpuHeadroom(eq(halParams1))).thenReturn(headroom1); + float[] headroom2 = new float[] {0.1f, 0.5f}; + when(mIPowerMock.getCpuHeadroom(eq(halParams2))).thenReturn(headroom2); + + HintManagerService service = createService(); + clearInvocations(mIPowerMock); + + service.getBinderServiceInstance().getCpuHeadroomMinIntervalMillis(); + verify(mIPowerMock, times(0)).getCpuHeadroomMinIntervalMillis(); + service.getBinderServiceInstance().getCpuHeadroom(params1); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1)); + service.getBinderServiceInstance().getCpuHeadroom(params2); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams2)); + + // verify cache is working + clearInvocations(mIPowerMock); + assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1), + 0.01f); + assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2), + 0.01f); + verify(mIPowerMock, times(0)).getCpuHeadroom(any()); + + // after 1 more second it should be served with cache still + Thread.sleep(1000); + clearInvocations(mIPowerMock); + assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1), + 0.01f); + assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2), + 0.01f); + verify(mIPowerMock, times(0)).getCpuHeadroom(any()); + + // after 1.5 more second it should be served with cache still as timer reset + Thread.sleep(1500); + clearInvocations(mIPowerMock); + assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1), + 0.01f); + assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2), + 0.01f); + verify(mIPowerMock, times(0)).getCpuHeadroom(any()); + + // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval + Thread.sleep(2100); + clearInvocations(mIPowerMock); + assertArrayEquals(headroom1, service.getBinderServiceInstance().getCpuHeadroom(params1), + 0.01f); + assertArrayEquals(headroom2, service.getBinderServiceInstance().getCpuHeadroom(params2), + 0.01f); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams1)); + verify(mIPowerMock, times(1)).getCpuHeadroom(eq(halParams2)); + } + + @Test + public void testGpuHeadroomCache() throws Exception { + when(mIPowerMock.getGpuHeadroomMinIntervalMillis()).thenReturn(2000L); + GpuHeadroomParamsInternal params1 = new GpuHeadroomParamsInternal(); + GpuHeadroomParams halParams1 = new GpuHeadroomParams(); + halParams1.calculationType = GpuHeadroomParams.CalculationType.MIN; + + GpuHeadroomParamsInternal params2 = new GpuHeadroomParamsInternal(); + GpuHeadroomParams halParams2 = new GpuHeadroomParams(); + params2.calculationType = + halParams2.calculationType = GpuHeadroomParams.CalculationType.AVERAGE; + + float headroom1 = 0.1f; + when(mIPowerMock.getGpuHeadroom(eq(halParams1))).thenReturn(headroom1); + float headroom2 = 0.2f; + when(mIPowerMock.getGpuHeadroom(eq(halParams2))).thenReturn(headroom2); + HintManagerService service = createService(); + clearInvocations(mIPowerMock); + + service.getBinderServiceInstance().getGpuHeadroomMinIntervalMillis(); + verify(mIPowerMock, times(0)).getGpuHeadroomMinIntervalMillis(); + assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1), + 0.01f); + assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2), + 0.01f); + verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1)); + verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); + + // verify cache is working + clearInvocations(mIPowerMock); + assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1), + 0.01f); + assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2), + 0.01f); + verify(mIPowerMock, times(0)).getGpuHeadroom(any()); + + // after 1 more second it should be served with cache still + Thread.sleep(1000); + clearInvocations(mIPowerMock); + assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1), + 0.01f); + assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2), + 0.01f); + verify(mIPowerMock, times(0)).getGpuHeadroom(any()); + + // after 1.5 more second it should be served with cache still as timer reset + Thread.sleep(1500); + clearInvocations(mIPowerMock); + assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1), + 0.01f); + assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2), + 0.01f); + verify(mIPowerMock, times(0)).getGpuHeadroom(any()); + + // after 2+ seconds it should be served from HAL as it exceeds 2000 millis interval + Thread.sleep(2100); + clearInvocations(mIPowerMock); + assertEquals(headroom1, service.getBinderServiceInstance().getGpuHeadroom(params1), + 0.01f); + assertEquals(headroom2, service.getBinderServiceInstance().getGpuHeadroom(params2), + 0.01f); + verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams1)); + verify(mIPowerMock, times(1)).getGpuHeadroom(eq(halParams2)); + } } diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java index 359cf6376239..b48c2d7f5007 100644 --- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java +++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java @@ -2705,12 +2705,11 @@ public class PowerManagerServiceTest { verify(mInvalidateInteractiveCachesMock).call(); listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId); - verify(mInvalidateInteractiveCachesMock, times(2)).call(); mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, mClock.now(), 0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null); - verify(mInvalidateInteractiveCachesMock, times(3)).call(); + verify(mInvalidateInteractiveCachesMock, times(2)).call(); } @Test @@ -2732,12 +2731,11 @@ public class PowerManagerServiceTest { verify(mInvalidateInteractiveCachesMock).call(); listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId); - verify(mInvalidateInteractiveCachesMock, times(2)).call(); mService.setWakefulnessLocked(nonDefaultDisplayGroupId, WAKEFULNESS_ASLEEP, mClock.now(), 0, PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0, null, null); - verify(mInvalidateInteractiveCachesMock, times(3)).call(); + verify(mInvalidateInteractiveCachesMock, times(2)).call(); } @Test diff --git a/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java b/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java index 40e00344f87a..03c449cc8d69 100644 --- a/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java +++ b/services/tests/security/forensic/src/com/android/server/security/forensic/ForensicServiceTest.java @@ -16,9 +16,13 @@ package com.android.server.security.forensic; +import static android.Manifest.permission.MANAGE_FORENSIC_STATE; +import static android.Manifest.permission.READ_FORENSIC_STATE; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -27,57 +31,63 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.annotation.SuppressLint; +import android.app.admin.ConnectEvent; +import android.app.admin.DnsEvent; +import android.app.admin.SecurityLog.SecurityEvent; import android.content.Context; import android.os.Looper; +import android.os.PermissionEnforcer; import android.os.RemoteException; +import android.os.test.FakePermissionEnforcer; import android.os.test.TestLooper; import android.security.forensic.ForensicEvent; import android.security.forensic.IForensicServiceCommandCallback; import android.security.forensic.IForensicServiceStateCallback; -import android.util.ArrayMap; import androidx.test.core.app.ApplicationProvider; import com.android.server.ServiceThread; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.mockito.ArgumentCaptor; import java.util.ArrayList; import java.util.List; -import java.util.Map; public class ForensicServiceTest { private static final int STATE_UNKNOWN = IForensicServiceStateCallback.State.UNKNOWN; - private static final int STATE_INVISIBLE = IForensicServiceStateCallback.State.INVISIBLE; - private static final int STATE_VISIBLE = IForensicServiceStateCallback.State.VISIBLE; + private static final int STATE_DISABLED = IForensicServiceStateCallback.State.DISABLED; private static final int STATE_ENABLED = IForensicServiceStateCallback.State.ENABLED; private static final int ERROR_UNKNOWN = IForensicServiceCommandCallback.ErrorCode.UNKNOWN; private static final int ERROR_PERMISSION_DENIED = IForensicServiceCommandCallback.ErrorCode.PERMISSION_DENIED; - private static final int ERROR_INVALID_STATE_TRANSITION = - IForensicServiceCommandCallback.ErrorCode.INVALID_STATE_TRANSITION; - private static final int ERROR_BACKUP_TRANSPORT_UNAVAILABLE = - IForensicServiceCommandCallback.ErrorCode.BACKUP_TRANSPORT_UNAVAILABLE; + private static final int ERROR_TRANSPORT_UNAVAILABLE = + IForensicServiceCommandCallback.ErrorCode.TRANSPORT_UNAVAILABLE; private static final int ERROR_DATA_SOURCE_UNAVAILABLE = IForensicServiceCommandCallback.ErrorCode.DATA_SOURCE_UNAVAILABLE; private Context mContext; - private BackupTransportConnection mBackupTransportConnection; + private ForensicEventTransportConnection mForensicEventTransportConnection; private DataAggregator mDataAggregator; private ForensicService mForensicService; private TestLooper mTestLooper; private Looper mLooper; private TestLooper mTestLooperOfDataAggregator; private Looper mLooperOfDataAggregator; + private FakePermissionEnforcer mPermissionEnforcer; @SuppressLint("VisibleForTests") @Before public void setUp() { mContext = spy(ApplicationProvider.getApplicationContext()); + mPermissionEnforcer = new FakePermissionEnforcer(); + mPermissionEnforcer.grant(READ_FORENSIC_STATE); + mPermissionEnforcer.grant(MANAGE_FORENSIC_STATE); + mTestLooper = new TestLooper(); mLooper = mTestLooper.getLooper(); mTestLooperOfDataAggregator = new TestLooper(); @@ -87,217 +97,101 @@ public class ForensicServiceTest { } @Test - public void testMonitorState_Invisible() throws RemoteException { + public void testAddStateCallback_NoPermission() { + mPermissionEnforcer.revoke(READ_FORENSIC_STATE); StateCallback scb = new StateCallback(); assertEquals(STATE_UNKNOWN, scb.mState); - mForensicService.getBinderService().monitorState(scb); - mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb.mState); - } - - @Test - public void testMonitorState_Invisible_TwoMonitors() throws RemoteException { - StateCallback scb1 = new StateCallback(); - assertEquals(STATE_UNKNOWN, scb1.mState); - mForensicService.getBinderService().monitorState(scb1); - mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - - StateCallback scb2 = new StateCallback(); - assertEquals(STATE_UNKNOWN, scb2.mState); - mForensicService.getBinderService().monitorState(scb2); - mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb2.mState); + assertThrows(SecurityException.class, + () -> mForensicService.getBinderService().addStateCallback(scb)); } @Test - public void testMakeVisible_FromInvisible() throws RemoteException { + public void testRemoveStateCallback_NoPermission() { + mPermissionEnforcer.revoke(READ_FORENSIC_STATE); StateCallback scb = new StateCallback(); assertEquals(STATE_UNKNOWN, scb.mState); - mForensicService.getBinderService().monitorState(scb); - mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb.mState); - - CommandCallback ccb = new CommandCallback(); - mForensicService.getBinderService().makeVisible(ccb); - mTestLooper.dispatchAll(); - assertEquals(STATE_VISIBLE, scb.mState); - assertNull(ccb.mErrorCode); + assertThrows(SecurityException.class, + () -> mForensicService.getBinderService().removeStateCallback(scb)); } @Test - public void testMakeVisible_FromInvisible_TwoMonitors() throws RemoteException { - mForensicService.setState(STATE_INVISIBLE); - StateCallback scb1 = new StateCallback(); - StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); - mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); - - doReturn(true).when(mDataAggregator).initialize(); - - CommandCallback ccb = new CommandCallback(); - mForensicService.getBinderService().makeVisible(ccb); - mTestLooper.dispatchAll(); - assertEquals(STATE_VISIBLE, scb1.mState); - assertEquals(STATE_VISIBLE, scb2.mState); - assertNull(ccb.mErrorCode); - } - - @Test - public void testMakeVisible_FromInvisible_TwoMonitors_DataSourceUnavailable() - throws RemoteException { - mForensicService.setState(STATE_INVISIBLE); - StateCallback scb1 = new StateCallback(); - StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); - mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); - - doReturn(false).when(mDataAggregator).initialize(); + public void testEnable_NoPermission() { + mPermissionEnforcer.revoke(MANAGE_FORENSIC_STATE); CommandCallback ccb = new CommandCallback(); - mForensicService.getBinderService().makeVisible(ccb); - mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); - assertNotNull(ccb.mErrorCode); - assertEquals(ERROR_DATA_SOURCE_UNAVAILABLE, ccb.mErrorCode.intValue()); + assertThrows(SecurityException.class, + () -> mForensicService.getBinderService().enable(ccb)); } @Test - public void testMakeVisible_FromVisible_TwoMonitors() throws RemoteException { - mForensicService.setState(STATE_VISIBLE); - StateCallback scb1 = new StateCallback(); - StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); - mTestLooper.dispatchAll(); - assertEquals(STATE_VISIBLE, scb1.mState); - assertEquals(STATE_VISIBLE, scb2.mState); + public void testDisable_NoPermission() { + mPermissionEnforcer.revoke(MANAGE_FORENSIC_STATE); CommandCallback ccb = new CommandCallback(); - mForensicService.getBinderService().makeVisible(ccb); - mTestLooper.dispatchAll(); - assertEquals(STATE_VISIBLE, scb1.mState); - assertEquals(STATE_VISIBLE, scb2.mState); - assertNull(ccb.mErrorCode); + assertThrows(SecurityException.class, + () -> mForensicService.getBinderService().disable(ccb)); } @Test - public void testMakeVisible_FromEnabled_TwoMonitors() throws RemoteException { - mForensicService.setState(STATE_ENABLED); - StateCallback scb1 = new StateCallback(); - StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); - mTestLooper.dispatchAll(); - assertEquals(STATE_ENABLED, scb1.mState); - assertEquals(STATE_ENABLED, scb2.mState); - - CommandCallback ccb = new CommandCallback(); - mForensicService.getBinderService().makeVisible(ccb); + public void testAddStateCallback_Disabled() throws RemoteException { + StateCallback scb = new StateCallback(); + assertEquals(STATE_UNKNOWN, scb.mState); + mForensicService.getBinderService().addStateCallback(scb); mTestLooper.dispatchAll(); - assertEquals(STATE_ENABLED, scb1.mState); - assertEquals(STATE_ENABLED, scb2.mState); - assertNotNull(ccb.mErrorCode); - assertEquals(ERROR_INVALID_STATE_TRANSITION, ccb.mErrorCode.intValue()); + assertEquals(STATE_DISABLED, scb.mState); } @Test - public void testMakeInvisible_FromInvisible_TwoMonitors() throws RemoteException { - mForensicService.setState(STATE_INVISIBLE); + public void testAddStateCallback_Disabled_TwoStateCallbacks() throws RemoteException { StateCallback scb1 = new StateCallback(); - StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); - mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); - - CommandCallback ccb = new CommandCallback(); - mForensicService.getBinderService().makeInvisible(ccb); + assertEquals(STATE_UNKNOWN, scb1.mState); + mForensicService.getBinderService().addStateCallback(scb1); mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); - assertNull(ccb.mErrorCode); - } + assertEquals(STATE_DISABLED, scb1.mState); - @Test - public void testMakeInvisible_FromVisible_TwoMonitors() throws RemoteException { - mForensicService.setState(STATE_VISIBLE); - StateCallback scb1 = new StateCallback(); StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); - mTestLooper.dispatchAll(); - assertEquals(STATE_VISIBLE, scb1.mState); - assertEquals(STATE_VISIBLE, scb2.mState); - - CommandCallback ccb = new CommandCallback(); - mForensicService.getBinderService().makeInvisible(ccb); + assertEquals(STATE_UNKNOWN, scb2.mState); + mForensicService.getBinderService().addStateCallback(scb2); mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); - assertNull(ccb.mErrorCode); + assertEquals(STATE_DISABLED, scb2.mState); } @Test - public void testMakeInvisible_FromEnabled_TwoMonitors() throws RemoteException { - mForensicService.setState(STATE_ENABLED); + public void testRemoveStateCallback() throws RemoteException { + mForensicService.setState(STATE_DISABLED); StateCallback scb1 = new StateCallback(); StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); + mForensicService.getBinderService().addStateCallback(scb1); + mForensicService.getBinderService().addStateCallback(scb2); mTestLooper.dispatchAll(); - assertEquals(STATE_ENABLED, scb1.mState); - assertEquals(STATE_ENABLED, scb2.mState); + assertEquals(STATE_DISABLED, scb1.mState); + assertEquals(STATE_DISABLED, scb2.mState); - CommandCallback ccb = new CommandCallback(); - mForensicService.getBinderService().makeInvisible(ccb); - mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); - assertNull(ccb.mErrorCode); - } + doReturn(true).when(mDataAggregator).initialize(); + doReturn(true).when(mForensicEventTransportConnection).initialize(); - - @Test - public void testEnable_FromInvisible_TwoMonitors() throws RemoteException { - mForensicService.setState(STATE_INVISIBLE); - StateCallback scb1 = new StateCallback(); - StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); - mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); + mForensicService.getBinderService().removeStateCallback(scb2); CommandCallback ccb = new CommandCallback(); mForensicService.getBinderService().enable(ccb); mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); - assertNotNull(ccb.mErrorCode); - assertEquals(ERROR_INVALID_STATE_TRANSITION, ccb.mErrorCode.intValue()); + assertEquals(STATE_ENABLED, scb1.mState); + assertEquals(STATE_DISABLED, scb2.mState); + assertNull(ccb.mErrorCode); } @Test - public void testEnable_FromVisible_TwoMonitors() throws RemoteException { - mForensicService.setState(STATE_VISIBLE); + public void testEnable_FromDisabled_TwoStateCallbacks() throws RemoteException { + mForensicService.setState(STATE_DISABLED); StateCallback scb1 = new StateCallback(); StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); + mForensicService.getBinderService().addStateCallback(scb1); + mForensicService.getBinderService().addStateCallback(scb2); mTestLooper.dispatchAll(); - assertEquals(STATE_VISIBLE, scb1.mState); - assertEquals(STATE_VISIBLE, scb2.mState); + assertEquals(STATE_DISABLED, scb1.mState); + assertEquals(STATE_DISABLED, scb2.mState); - doReturn(true).when(mBackupTransportConnection).initialize(); + doReturn(true).when(mForensicEventTransportConnection).initialize(); CommandCallback ccb = new CommandCallback(); mForensicService.getBinderService().enable(ccb); @@ -310,35 +204,13 @@ public class ForensicServiceTest { } @Test - public void testEnable_FromVisible_TwoMonitors_BackupTransportUnavailable() + public void testEnable_FromEnabled_TwoStateCallbacks() throws RemoteException { - mForensicService.setState(STATE_VISIBLE); - StateCallback scb1 = new StateCallback(); - StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); - mTestLooper.dispatchAll(); - assertEquals(STATE_VISIBLE, scb1.mState); - assertEquals(STATE_VISIBLE, scb2.mState); - - doReturn(false).when(mBackupTransportConnection).initialize(); - - CommandCallback ccb = new CommandCallback(); - mForensicService.getBinderService().enable(ccb); - mTestLooper.dispatchAll(); - assertEquals(STATE_VISIBLE, scb1.mState); - assertEquals(STATE_VISIBLE, scb2.mState); - assertNotNull(ccb.mErrorCode); - assertEquals(ERROR_BACKUP_TRANSPORT_UNAVAILABLE, ccb.mErrorCode.intValue()); - } - - @Test - public void testEnable_FromEnabled_TwoMonitors() throws RemoteException { mForensicService.setState(STATE_ENABLED); StateCallback scb1 = new StateCallback(); StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); + mForensicService.getBinderService().addStateCallback(scb1); + mForensicService.getBinderService().addStateCallback(scb2); mTestLooper.dispatchAll(); assertEquals(STATE_ENABLED, scb1.mState); assertEquals(STATE_ENABLED, scb2.mState); @@ -346,62 +218,44 @@ public class ForensicServiceTest { CommandCallback ccb = new CommandCallback(); mForensicService.getBinderService().enable(ccb); mTestLooper.dispatchAll(); + assertEquals(STATE_ENABLED, scb1.mState); assertEquals(STATE_ENABLED, scb2.mState); assertNull(ccb.mErrorCode); } @Test - public void testDisable_FromInvisible_TwoMonitors() throws RemoteException { - mForensicService.setState(STATE_INVISIBLE); + public void testDisable_FromDisabled_TwoStateCallbacks() throws RemoteException { + mForensicService.setState(STATE_DISABLED); StateCallback scb1 = new StateCallback(); StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); + mForensicService.getBinderService().addStateCallback(scb1); + mForensicService.getBinderService().addStateCallback(scb2); mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); + assertEquals(STATE_DISABLED, scb1.mState); + assertEquals(STATE_DISABLED, scb2.mState); CommandCallback ccb = new CommandCallback(); mForensicService.getBinderService().disable(ccb); mTestLooper.dispatchAll(); - assertEquals(STATE_INVISIBLE, scb1.mState); - assertEquals(STATE_INVISIBLE, scb2.mState); - assertNotNull(ccb.mErrorCode); - assertEquals(ERROR_INVALID_STATE_TRANSITION, ccb.mErrorCode.intValue()); - } - - @Test - public void testDisable_FromVisible_TwoMonitors() throws RemoteException { - mForensicService.setState(STATE_VISIBLE); - StateCallback scb1 = new StateCallback(); - StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); - mTestLooper.dispatchAll(); - assertEquals(STATE_VISIBLE, scb1.mState); - assertEquals(STATE_VISIBLE, scb2.mState); - CommandCallback ccb = new CommandCallback(); - mForensicService.getBinderService().disable(ccb); - mTestLooper.dispatchAll(); - assertEquals(STATE_VISIBLE, scb1.mState); - assertEquals(STATE_VISIBLE, scb2.mState); + assertEquals(STATE_DISABLED, scb1.mState); + assertEquals(STATE_DISABLED, scb2.mState); assertNull(ccb.mErrorCode); } @Test - public void testDisable_FromEnabled_TwoMonitors() throws RemoteException { + public void testDisable_FromEnabled_TwoStateCallbacks() throws RemoteException { mForensicService.setState(STATE_ENABLED); StateCallback scb1 = new StateCallback(); StateCallback scb2 = new StateCallback(); - mForensicService.getBinderService().monitorState(scb1); - mForensicService.getBinderService().monitorState(scb2); + mForensicService.getBinderService().addStateCallback(scb1); + mForensicService.getBinderService().addStateCallback(scb2); mTestLooper.dispatchAll(); assertEquals(STATE_ENABLED, scb1.mState); assertEquals(STATE_ENABLED, scb2.mState); - doNothing().when(mBackupTransportConnection).release(); + doNothing().when(mForensicEventTransportConnection).release(); ServiceThread mockThread = spy(ServiceThread.class); mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread); @@ -412,56 +266,74 @@ public class ForensicServiceTest { mTestLooperOfDataAggregator.dispatchAll(); // TODO: We can verify the data sources once we implement them. verify(mockThread, times(1)).quitSafely(); - assertEquals(STATE_VISIBLE, scb1.mState); - assertEquals(STATE_VISIBLE, scb2.mState); + assertEquals(STATE_DISABLED, scb1.mState); + assertEquals(STATE_DISABLED, scb2.mState); assertNull(ccb.mErrorCode); } + @Ignore("Enable once the ForensicEventTransportConnection is ready") + @Test + public void testEnable_FromDisable_TwoStateCallbacks_TransportUnavailable() + throws RemoteException { + mForensicService.setState(STATE_DISABLED); + StateCallback scb1 = new StateCallback(); + StateCallback scb2 = new StateCallback(); + mForensicService.getBinderService().addStateCallback(scb1); + mForensicService.getBinderService().addStateCallback(scb2); + mTestLooper.dispatchAll(); + assertEquals(STATE_DISABLED, scb1.mState); + assertEquals(STATE_DISABLED, scb2.mState); + + doReturn(false).when(mForensicEventTransportConnection).initialize(); + + CommandCallback ccb = new CommandCallback(); + mForensicService.getBinderService().enable(ccb); + mTestLooper.dispatchAll(); + assertEquals(STATE_DISABLED, scb1.mState); + assertEquals(STATE_DISABLED, scb2.mState); + assertNotNull(ccb.mErrorCode); + assertEquals(ERROR_TRANSPORT_UNAVAILABLE, ccb.mErrorCode.intValue()); + } + @Test public void testDataAggregator_AddBatchData() { mForensicService.setState(STATE_ENABLED); ServiceThread mockThread = spy(ServiceThread.class); mDataAggregator.setHandler(mLooperOfDataAggregator, mockThread); - String eventOneType = "event_one_type"; - String eventOneMapKey = "event_one_map_key"; - String eventOneMapVal = "event_one_map_val"; - Map<String, String> eventOneMap = new ArrayMap<String, String>(); - eventOneMap.put(eventOneMapKey, eventOneMapVal); - ForensicEvent eventOne = new ForensicEvent(eventOneType, eventOneMap); + SecurityEvent securityEvent = new SecurityEvent(0, new byte[0]); + ForensicEvent eventOne = new ForensicEvent(securityEvent); - String eventTwoType = "event_two_type"; - String eventTwoMapKey = "event_two_map_key"; - String eventTwoMapVal = "event_two_map_val"; - Map<String, String> eventTwoMap = new ArrayMap<String, String>(); - eventTwoMap.put(eventTwoMapKey, eventTwoMapVal); - ForensicEvent eventTwo = new ForensicEvent(eventTwoType, eventTwoMap); + ConnectEvent connectEvent = new ConnectEvent("127.0.0.1", 80, null, 0); + ForensicEvent eventTwo = new ForensicEvent(connectEvent); + + DnsEvent dnsEvent = new DnsEvent(null, new String[] {"127.0.0.1"}, 1, null, 0); + ForensicEvent eventThree = new ForensicEvent(dnsEvent); List<ForensicEvent> events = new ArrayList<>(); events.add(eventOne); events.add(eventTwo); + events.add(eventThree); - doReturn(true).when(mBackupTransportConnection).addData(any()); + doReturn(true).when(mForensicEventTransportConnection).addData(any()); mDataAggregator.addBatchData(events); mTestLooperOfDataAggregator.dispatchAll(); mTestLooper.dispatchAll(); ArgumentCaptor<List<ForensicEvent>> captor = ArgumentCaptor.forClass(List.class); - verify(mBackupTransportConnection).addData(captor.capture()); + verify(mForensicEventTransportConnection).addData(captor.capture()); List<ForensicEvent> receivedEvents = captor.getValue(); - assertEquals(receivedEvents.size(), 2); + assertEquals(receivedEvents.size(), 3); - assertEquals(receivedEvents.getFirst().getType(), eventOneType); - assertEquals(receivedEvents.getFirst().getKeyValuePairs().size(), 1); - assertEquals(receivedEvents.getFirst().getKeyValuePairs().get(eventOneMapKey), - eventOneMapVal); + assertEquals(receivedEvents.get(0).getType(), ForensicEvent.SECURITY_EVENT); + assertNotNull(receivedEvents.get(0).getSecurityEvent()); - assertEquals(receivedEvents.getLast().getType(), eventTwoType); - assertEquals(receivedEvents.getLast().getKeyValuePairs().size(), 1); - assertEquals(receivedEvents.getLast().getKeyValuePairs().get(eventTwoMapKey), - eventTwoMapVal); + assertEquals(receivedEvents.get(1).getType(), ForensicEvent.NETWORK_EVENT_CONNECT); + assertNotNull(receivedEvents.get(1).getConnectEvent()); + assertEquals(receivedEvents.get(2).getType(), ForensicEvent.NETWORK_EVENT_DNS); + assertNotNull(receivedEvents.get(2).getDnsEvent()); } private class MockInjector implements ForensicService.Injector { @@ -476,6 +348,10 @@ public class ForensicServiceTest { return mContext; } + @Override + public PermissionEnforcer getPermissionEnforcer() { + return mPermissionEnforcer; + } @Override public Looper getLooper() { @@ -483,9 +359,9 @@ public class ForensicServiceTest { } @Override - public BackupTransportConnection getBackupTransportConnection() { - mBackupTransportConnection = spy(new BackupTransportConnection(mContext)); - return mBackupTransportConnection; + public ForensicEventTransportConnection getForensicEventransportConnection() { + mForensicEventTransportConnection = spy(new ForensicEventTransportConnection(mContext)); + return mForensicEventTransportConnection; } @Override diff --git a/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java index 0988eeab5913..a55346caeeb1 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/FlashNotificationsControllerTest.java @@ -430,7 +430,7 @@ public class FlashNotificationsControllerTest { AudioPlaybackConfiguration config = new AudioPlaybackConfiguration( mock(PlayerBase.PlayerIdCard.class), 0, 0, 0); config.handleStateEvent(AudioPlaybackConfiguration.PLAYER_STATE_STARTED, - AudioPlaybackConfiguration.PLAYER_DEVICEID_INVALID); + AudioPlaybackConfiguration.PLAYER_DEVICEIDS_INVALID); AudioAttributes.Builder builder = new AudioAttributes.Builder(); builder.setUsage(AudioAttributes.USAGE_ALARM); diff --git a/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java b/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java index 84c0ab38ca48..0d44021bae09 100644 --- a/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/audio/LoudnessCodecHelperTest.java @@ -314,12 +314,13 @@ public class LoudnessCodecHelperTest { AudioDeviceInfo[] devicesStatic = AudioManager.getDevicesStatic(GET_DEVICES_OUTPUTS); assumeTrue(devIdx < devicesStatic.length); Log.d(TAG, "Out devices number " + devicesStatic.length + ". Picking index " + devIdx); - int deviceId = devicesStatic[devIdx].getId(); + int[] deviceIds = new int[1]; + deviceIds[0] = devicesStatic[devIdx].getId(); PlayerBase.PlayerIdCard idCard = Mockito.mock(PlayerBase.PlayerIdCard.class); AudioPlaybackConfiguration apc = new AudioPlaybackConfiguration(idCard, piid, /*uid=*/1, /*pid=*/myPid()); - apc.handleStateEvent(PLAYER_UPDATE_DEVICE_ID, deviceId); + apc.handleStateEvent(PLAYER_UPDATE_DEVICE_ID, deviceIds); apc.handleSessionIdEvent(sessionId); apc.handleAudioAttributesEvent(new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) diff --git a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java index b81bf3c6e712..f6f831f41f83 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/PreAuthInfoTest.java @@ -21,6 +21,7 @@ import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE; import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS; +import static android.hardware.biometrics.BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE; import static com.android.server.biometrics.sensors.LockoutTracker.LOCKOUT_NONE; @@ -354,6 +355,21 @@ public class PreAuthInfoTest { assertThat(preAuthInfo.getIsMandatoryBiometricsAuthentication()).isTrue(); } + @Test + public void prioritizeStrengthErrorBeforeCameraUnavailableError() throws Exception { + final BiometricSensor sensor = getFaceSensorWithStrength( + BiometricManager.Authenticators.BIOMETRIC_WEAK); + final PromptInfo promptInfo = new PromptInfo(); + promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG); + promptInfo.setNegativeButtonText(TEST_PACKAGE_NAME); + final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager, + mSettingObserver, List.of(sensor), USER_ID , promptInfo, TEST_PACKAGE_NAME, + false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager, + mUserManager); + + assertThat(preAuthInfo.getCanAuthenticateResult()).isEqualTo(BIOMETRIC_ERROR_NO_HARDWARE); + } + private BiometricSensor getFingerprintSensor() { BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FINGERPRINT, TYPE_FINGERPRINT, BiometricManager.Authenticators.BIOMETRIC_STRONG, @@ -372,9 +388,10 @@ public class PreAuthInfoTest { return sensor; } - private BiometricSensor getFaceSensor() { + private BiometricSensor getFaceSensorWithStrength( + @BiometricManager.Authenticators.Types int sensorStrength) { BiometricSensor sensor = new BiometricSensor(mContext, SENSOR_ID_FACE, TYPE_FACE, - BiometricManager.Authenticators.BIOMETRIC_STRONG, mFaceAuthenticator) { + sensorStrength, mFaceAuthenticator) { @Override boolean confirmationAlwaysRequired(int userId) { return false; @@ -388,4 +405,8 @@ public class PreAuthInfoTest { return sensor; } + + private BiometricSensor getFaceSensor() { + return getFaceSensorWithStrength(BiometricManager.Authenticators.BIOMETRIC_STRONG); + } } diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java index 51c2ad1d1134..687a1ab4c7aa 100644 --- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java @@ -200,7 +200,9 @@ public class VirtualAudioControllerTest { AudioPlaybackConfiguration audioPlaybackConfiguration = new AudioPlaybackConfiguration( playerIdCard, /* piid= */ 1000, appUid, /* pid= */ 1000); - audioPlaybackConfiguration.handleStateEvent(PLAYER_STATE_STARTED, /* deviceId= */1); + int[] deviceIds = new int[1]; + deviceIds[0] = 1; + audioPlaybackConfiguration.handleStateEvent(PLAYER_STATE_STARTED, deviceIds); configs.add(audioPlaybackConfiguration); } return configs; diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index 698bda335f83..4c381eb4429e 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -24,6 +24,7 @@ import android.app.PendingIntent; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.DevicePolicyManagerLiteInternal; import android.app.backup.IBackupManager; +import android.app.supervision.SupervisionManagerInternal; import android.app.usage.UsageStatsManagerInternal; import android.content.Context; import android.content.Intent; @@ -488,6 +489,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi public Context createContextAsUser(UserHandle user) { return context; } + + @Override + SupervisionManagerInternal getSupervisionManager() { + return services.supervisionManagerInternal; + } } static class TransferOwnershipMetadataManagerMockInjector extends diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index cb4269a205e4..cf5dc4bec71c 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -109,6 +109,7 @@ import android.app.admin.PasswordMetrics; import android.app.admin.PreferentialNetworkServiceConfig; import android.app.admin.SystemUpdatePolicy; import android.app.admin.WifiSsidPolicy; +import android.app.admin.flags.Flags; import android.app.role.RoleManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -134,6 +135,10 @@ import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.Presubmit; +import android.platform.test.annotations.RequiresFlagsDisabled; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.DeviceConfig; import android.provider.Settings; import android.security.KeyChain; @@ -165,6 +170,7 @@ import org.hamcrest.Matcher; import org.junit.After; import org.junit.Before; import org.junit.Ignore; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mockito; import org.mockito.internal.util.collections.Sets; @@ -207,6 +213,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { public static final String INVALID_CALLING_IDENTITY_MSG = "Calling identity is not authorized"; public static final String ONGOING_CALL_MSG = "ongoing call on the device"; + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + // TODO replace all instances of this with explicit {@link #mServiceContext}. @Deprecated private DpmMockContext mContext; @@ -4425,6 +4434,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @Ignore("b/359188869") public void testSetAutoTimeEnabledWithPOOfOrganizationOwnedDevice() throws Exception { setupProfileOwner(); configureProfileOwnerOfOrgOwnedDevice(admin1, CALLER_USER_HANDLE); @@ -4902,6 +4912,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED) public void testSecondaryLockscreen_profileOwner() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_UID; @@ -4930,6 +4941,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED) public void testSecondaryLockscreen_deviceOwner() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; @@ -4948,6 +4960,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED) public void testSecondaryLockscreen_nonOwner() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_UID; @@ -4964,6 +4977,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @RequiresFlagsDisabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED) public void testSecondaryLockscreen_nonSupervisionApp() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_UID; @@ -4996,6 +5010,51 @@ public class DevicePolicyManagerTest extends DpmTestBase { } @Test + @RequiresFlagsEnabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED) + public void testIsSecondaryLockscreenEnabled() throws Exception { + mContext.binder.callingUid = DpmMockContext.CALLER_UID; + + verifyIsSecondaryLockscreenEnabled(false); + verifyIsSecondaryLockscreenEnabled(true); + } + + private void verifyIsSecondaryLockscreenEnabled(boolean expected) throws Exception { + reset(getServices().supervisionManagerInternal); + + doReturn(expected).when(getServices().supervisionManagerInternal) + .isSupervisionLockscreenEnabledForUser(anyInt()); + + final boolean enabled = dpm.isSecondaryLockscreenEnabled(UserHandle.of(CALLER_USER_HANDLE)); + verify(getServices().supervisionManagerInternal) + .isSupervisionLockscreenEnabledForUser(CALLER_USER_HANDLE); + + assertThat(enabled).isEqualTo(expected); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_SECONDARY_LOCKSCREEN_API_ENABLED) + public void testSetSecondaryLockscreenEnabled() throws Exception { + mContext.binder.callingUid = DpmMockContext.CALLER_UID; + + verifySetSecondaryLockscreenEnabled(false); + verifySetSecondaryLockscreenEnabled(true); + } + + private void verifySetSecondaryLockscreenEnabled(boolean enabled) throws Exception { + reset(getServices().supervisionManagerInternal); + + dpm.setSecondaryLockscreenEnabled(admin1, enabled); + verify(getServices().supervisionManagerInternal).setSupervisionLockscreenEnabledForUser( + CALLER_USER_HANDLE, enabled, null); + + reset(getServices().supervisionManagerInternal); + + dpm.setSecondaryLockscreenEnabled(enabled, new PersistableBundle()); + verify(getServices().supervisionManagerInternal).setSupervisionLockscreenEnabledForUser( + eq(CALLER_USER_HANDLE), eq(enabled), any(PersistableBundle.class)); + } + + @Test public void testIsDeviceManaged() throws Exception { mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; setupDeviceOwner(); diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java index 2e200a9268f5..3e4448c1dafa 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java @@ -35,6 +35,7 @@ import android.app.NotificationManager; import android.app.admin.DevicePolicyManager; import android.app.backup.IBackupManager; import android.app.role.RoleManager; +import android.app.supervision.SupervisionManagerInternal; import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -77,8 +78,8 @@ import com.android.internal.util.test.FakeSettingsProvider; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockSettingsInternal; import com.android.server.AlarmManagerInternal; -import com.android.server.pdb.PersistentDataBlockManagerInternal; import com.android.server.net.NetworkPolicyManagerInternal; +import com.android.server.pdb.PersistentDataBlockManagerInternal; import com.android.server.pm.PackageManagerLocal; import com.android.server.pm.UserManagerInternal; import com.android.server.pm.pkg.PackageState; @@ -149,6 +150,7 @@ public class MockSystemServices { public final BuildMock buildMock = new BuildMock(); public final File dataDir; public final PolicyPathProvider pathProvider; + public final SupervisionManagerInternal supervisionManagerInternal; private final Map<String, PackageState> mTestPackageStates = new ArrayMap<>(); @@ -203,6 +205,7 @@ public class MockSystemServices { roleManager = realContext.getSystemService(RoleManager.class); roleManagerForMock = mock(RoleManagerForMock.class); subscriptionManager = mock(SubscriptionManager.class); + supervisionManagerInternal = mock(SupervisionManagerInternal.class); // Package manager is huge, so we use a partial mock instead. packageManager = spy(realContext.getPackageManager()); diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java index 73aec6375a03..510c2bcabad0 100644 --- a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionManagerServiceTest.java @@ -532,6 +532,8 @@ public class MediaProjectionManagerServiceTest { MediaProjectionManagerService.MediaProjection projection = startProjectionPreconditions(); projection.start(mIMediaProjectionCallback); + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, projection.packageName); doReturn(true).when(mKeyguardManager).isKeyguardLocked(); MediaProjectionManagerService.BinderService mediaProjectionBinderService = mService.new BinderService(mContext); @@ -540,50 +542,6 @@ public class MediaProjectionManagerServiceTest { verify(mContext, never()).startActivityAsUser(any(), any()); } - @EnableFlags(android.companion.virtualdevice.flags - .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS) - @Test - public void testKeyguardLocked_stopsActiveProjection() throws Exception { - MediaProjectionManagerService service = - new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector); - MediaProjectionManagerService.MediaProjection projection = - startProjectionPreconditions(service); - projection.start(mIMediaProjectionCallback); - projection.notifyVirtualDisplayCreated(10); - - assertThat(service.getActiveProjectionInfo()).isNotNull(); - - doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager) - .checkPermission(RECORD_SENSITIVE_CONTENT, projection.packageName); - service.onKeyguardLockedStateChanged(true); - - verify(mMediaProjectionMetricsLogger).logStopped(UID, TARGET_UID_UNKNOWN); - assertThat(service.getActiveProjectionInfo()).isNull(); - assertThat(mIMediaProjectionCallback.mLatch.await(5, TimeUnit.SECONDS)).isTrue(); - } - - @EnableFlags(android.companion.virtualdevice.flags - .Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS) - @Test - public void testKeyguardLocked_packageAllowlisted_doesNotStopActiveProjection() - throws NameNotFoundException { - MediaProjectionManagerService service = - new MediaProjectionManagerService(mContext, mMediaProjectionMetricsLoggerInjector); - MediaProjectionManagerService.MediaProjection projection = - startProjectionPreconditions(service); - projection.start(mIMediaProjectionCallback); - projection.notifyVirtualDisplayCreated(10); - - assertThat(service.getActiveProjectionInfo()).isNotNull(); - - doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission( - RECORD_SENSITIVE_CONTENT, projection.packageName); - service.onKeyguardLockedStateChanged(true); - - verifyZeroInteractions(mMediaProjectionMetricsLogger); - assertThat(service.getActiveProjectionInfo()).isNotNull(); - } - @Test public void stop_noActiveProjections_doesNotLog() throws Exception { MediaProjectionManagerService service = diff --git a/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java new file mode 100644 index 000000000000..affcfc14034e --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/media/projection/MediaProjectionStopControllerTest.java @@ -0,0 +1,468 @@ +/* + * 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.media.projection; + + +import static android.Manifest.permission.RECORD_SENSITIVE_CONTENT; +import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS; +import static android.view.Display.INVALID_DISPLAY; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doReturn; +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; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.ActivityManagerInternal; +import android.app.AppOpsManager; +import android.app.Instrumentation; +import android.app.KeyguardManager; +import android.app.role.RoleManager; +import android.companion.AssociationRequest; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.ApplicationInfoFlags; +import android.content.pm.PackageManager.NameNotFoundException; +import android.media.projection.MediaProjectionManager; +import android.os.UserHandle; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; +import android.provider.Settings; +import android.telecom.TelecomManager; +import android.testing.TestableContext; +import android.util.ArraySet; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.server.LocalServices; +import com.android.server.SystemConfig; +import com.android.server.wm.WindowManagerInternal; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.Objects; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +/** + * Tests for the {@link MediaProjectionStopController} class. + * <p> + * Build/Install/Run: + * atest FrameworksServicesTests:MediaProjectionStopControllerTest + */ +@SmallTest +@Presubmit +@RunWith(AndroidJUnit4.class) +@SuppressLint({"UseCheckPermission", "VisibleForTests", "MissingPermission"}) +public class MediaProjectionStopControllerTest { + private static final int UID = 10; + private static final String PACKAGE_NAME = "test.package"; + private final ApplicationInfo mAppInfo = new ApplicationInfo(); + @Rule + public final TestableContext mContext = spy( + new TestableContext(InstrumentationRegistry.getInstrumentation().getContext())); + + private final MediaProjectionManagerService.Injector mMediaProjectionMetricsLoggerInjector = + new MediaProjectionManagerService.Injector() { + @Override + MediaProjectionMetricsLogger mediaProjectionMetricsLogger(Context context) { + return mMediaProjectionMetricsLogger; + } + }; + + private MediaProjectionManagerService mService; + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + @Mock + private ActivityManagerInternal mAmInternal; + @Mock + private PackageManager mPackageManager; + @Mock + private KeyguardManager mKeyguardManager; + @Mock + private TelecomManager mTelecomManager; + + private AppOpsManager mAppOpsManager; + @Mock + private MediaProjectionMetricsLogger mMediaProjectionMetricsLogger; + @Mock + private Consumer<Integer> mStopConsumer; + + private MediaProjectionStopController mStopController; + + @Before + public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + + LocalServices.removeServiceForTest(ActivityManagerInternal.class); + LocalServices.addService(ActivityManagerInternal.class, mAmInternal); + + mAppOpsManager = mockAppOpsManager(); + mContext.addMockSystemService(AppOpsManager.class, mAppOpsManager); + mContext.addMockSystemService(KeyguardManager.class, mKeyguardManager); + mContext.addMockSystemService(TelecomManager.class, mTelecomManager); + mContext.setMockPackageManager(mPackageManager); + + mStopController = new MediaProjectionStopController(mContext, mStopConsumer); + mService = new MediaProjectionManagerService(mContext, + mMediaProjectionMetricsLoggerInjector); + + mAppInfo.targetSdkVersion = 35; + } + + private static AppOpsManager mockAppOpsManager() { + return mock(AppOpsManager.class, invocationOnMock -> { + if (invocationOnMock.getMethod().getName().startsWith("noteOp")) { + // Mockito will return 0 for non-stubbed method which corresponds to MODE_ALLOWED + // and is not what we want. + return AppOpsManager.MODE_IGNORED; + } + return Answers.RETURNS_DEFAULTS.answer(invocationOnMock); + }); + } + + @After + public void tearDown() { + LocalServices.removeServiceForTest(ActivityManagerInternal.class); + LocalServices.removeServiceForTest(WindowManagerInternal.class); + } + + @Test + @EnableFlags( + android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS) + public void testMediaProjectionNotRestricted() throws Exception { + when(mKeyguardManager.isKeyguardLocked()).thenReturn(false); + + assertThat(mStopController.isStartForbidden( + createMediaProjection(PACKAGE_NAME))).isFalse(); + } + + @Test + @EnableFlags( + android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS) + public void testMediaProjectionRestricted() throws Exception { + MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(); + mediaProjection.notifyVirtualDisplayCreated(1); + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, mediaProjection.packageName); + when(mKeyguardManager.isKeyguardLocked()).thenReturn(true); + + assertThat(mStopController.isStartForbidden(mediaProjection)).isTrue(); + } + + @Test + public void testExemptFromStoppingNullProjection() throws Exception { + assertThat(mStopController.isExemptFromStopping(null, + MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue(); + } + + @Test + public void testExemptFromStoppingInvalidProjection() throws Exception { + assertThat(mStopController.isExemptFromStopping(createMediaProjection(null), + MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue(); + } + + @Test + public void testExemptFromStoppingDisableScreenshareProtections() throws Exception { + MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(); + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, mediaProjection.packageName); + int value = Settings.Global.getInt(mContext.getContentResolver(), + DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0); + try { + Settings.Global.putInt(mContext.getContentResolver(), + DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 1); + + assertThat(mStopController.isExemptFromStopping(mediaProjection, + MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue(); + } finally { + Settings.Global.putInt(mContext.getContentResolver(), + DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, value); + } + } + + @Test + public void testExemptFromStoppingHasOpProjectMedia() throws Exception { + MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(); + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, mediaProjection.packageName); + doReturn(AppOpsManager.MODE_ALLOWED).when(mAppOpsManager) + .noteOpNoThrow(eq(AppOpsManager.OP_PROJECT_MEDIA), + eq(mediaProjection.uid), eq(mediaProjection.packageName), + nullable(String.class), + nullable(String.class)); + assertThat(mStopController.isExemptFromStopping(mediaProjection, + MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue(); + } + + @Test + public void testExemptFromStoppingHasAppStreamingRole() throws Exception { + runWithRole( + AssociationRequest.DEVICE_PROFILE_APP_STREAMING, + () -> { + try { + MediaProjectionManagerService.MediaProjection mediaProjection = + createMediaProjection(); + doReturn(PackageManager.PERMISSION_DENIED).when( + mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, mediaProjection.packageName); + assertThat(mStopController.isExemptFromStopping(mediaProjection, + MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue(); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } + + @Test + public void testExemptFromStoppingIsBugreportAllowlisted() throws Exception { + ArraySet<String> packages = SystemConfig.getInstance().getBugreportWhitelistedPackages(); + if (packages.isEmpty()) { + return; + } + MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection( + packages.valueAt(0)); + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, mediaProjection.packageName); + assertThat(mStopController.isExemptFromStopping(mediaProjection, + MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue(); + } + + @Test + public void testExemptFromStoppingHasNoDisplay() throws Exception { + MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection( + PACKAGE_NAME); + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, mediaProjection.packageName); + assertThat(mStopController.isExemptFromStopping(mediaProjection, + MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue(); + } + + @Test + public void testExemptFromStoppingHasRecordSensitiveContentPermission() throws Exception { + MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(); + doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, mediaProjection.packageName); + assertThat(mStopController.isExemptFromStopping(mediaProjection, + MediaProjectionStopController.STOP_REASON_UNKNOWN)).isTrue(); + } + + @Test + public void testExemptFromStoppingIsFalse() throws Exception { + MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(); + mediaProjection.notifyVirtualDisplayCreated(1); + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, mediaProjection.packageName); + assertThat(mStopController.isExemptFromStopping(mediaProjection, + MediaProjectionStopController.STOP_REASON_UNKNOWN)).isFalse(); + } + + @Test + @EnableFlags( + android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS) + public void testKeyguardLockedStateChanged_unlocked() { + mStopController.onKeyguardLockedStateChanged(false); + + verify(mStopConsumer, never()).accept(anyInt()); + } + + @Test + @EnableFlags( + android.companion.virtualdevice.flags.Flags.FLAG_MEDIA_PROJECTION_KEYGUARD_RESTRICTIONS) + public void testKeyguardLockedStateChanged_locked() { + mStopController.onKeyguardLockedStateChanged(true); + + verify(mStopConsumer).accept(MediaProjectionStopController.STOP_REASON_KEYGUARD); + } + + @Test + @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END) + public void testCallStateChanged_callStarts() { + // Setup call state to false + when(mTelecomManager.isInCall()).thenReturn(false); + mStopController.callStateChanged(); + + clearInvocations(mStopConsumer); + + when(mTelecomManager.isInCall()).thenReturn(true); + mStopController.callStateChanged(); + + verify(mStopConsumer, never()).accept(anyInt()); + } + + @Test + @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END) + public void testCallStateChanged_remainsInCall() { + // Setup call state to false + when(mTelecomManager.isInCall()).thenReturn(true); + mStopController.callStateChanged(); + + clearInvocations(mStopConsumer); + + when(mTelecomManager.isInCall()).thenReturn(true); + mStopController.callStateChanged(); + + verify(mStopConsumer, never()).accept(anyInt()); + } + + @Test + @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END) + public void testCallStateChanged_remainsNoCall() { + // Setup call state to false + when(mTelecomManager.isInCall()).thenReturn(false); + mStopController.callStateChanged(); + + clearInvocations(mStopConsumer); + + when(mTelecomManager.isInCall()).thenReturn(false); + mStopController.callStateChanged(); + + verify(mStopConsumer, never()).accept(anyInt()); + } + + @Test + @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END) + public void testCallStateChanged_callEnds() { + // Setup call state to false + when(mTelecomManager.isInCall()).thenReturn(true); + mStopController.callStateChanged(); + + clearInvocations(mStopConsumer); + + when(mTelecomManager.isInCall()).thenReturn(false); + mStopController.callStateChanged(); + + verify(mStopConsumer).accept(MediaProjectionStopController.STOP_REASON_CALL_END); + } + + @Test + @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END) + public void testExemptFromStopping_callEnd_callBeforeMediaProjection() throws Exception { + when(mTelecomManager.isInCall()).thenReturn(true); + mStopController.callStateChanged(); + + MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(); + mediaProjection.notifyVirtualDisplayCreated(1); + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, mediaProjection.packageName); + + assertThat(mStopController.isExemptFromStopping(mediaProjection, + MediaProjectionStopController.STOP_REASON_CALL_END)).isFalse(); + } + + @Test + @EnableFlags(com.android.media.projection.flags.Flags.FLAG_STOP_MEDIA_PROJECTION_ON_CALL_END) + public void testExemptFromStopping_callEnd_callAfterMediaProjection() throws Exception { + MediaProjectionManagerService.MediaProjection mediaProjection = createMediaProjection(); + mediaProjection.notifyVirtualDisplayCreated(1); + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + RECORD_SENSITIVE_CONTENT, mediaProjection.packageName); + + when(mTelecomManager.isInCall()).thenReturn(true); + mStopController.callStateChanged(); + + assertThat(mStopController.isExemptFromStopping(mediaProjection, + MediaProjectionStopController.STOP_REASON_CALL_END)).isTrue(); + } + + private MediaProjectionManagerService.MediaProjection createMediaProjection() + throws NameNotFoundException { + return createMediaProjection(PACKAGE_NAME); + } + + private MediaProjectionManagerService.MediaProjection createMediaProjection(String packageName) + throws NameNotFoundException { + doReturn(mAppInfo).when(mPackageManager).getApplicationInfoAsUser(anyString(), + any(ApplicationInfoFlags.class), any(UserHandle.class)); + doReturn(mAppInfo).when(mPackageManager).getApplicationInfoAsUser(Mockito.isNull(), + any(ApplicationInfoFlags.class), any(UserHandle.class)); + return mService.createProjectionInternal(UID, packageName, + MediaProjectionManager.TYPE_SCREEN_CAPTURE, false, mContext.getUser(), + INVALID_DISPLAY); + } + + /** + * Run the provided block giving the current context's package the provided role. + */ + @SuppressWarnings("SameParameterValue") + private void runWithRole(String role, Runnable block) { + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + String packageName = mContext.getPackageName(); + UserHandle user = instrumentation.getTargetContext().getUser(); + RoleManager roleManager = Objects.requireNonNull( + mContext.getSystemService(RoleManager.class)); + try { + CountDownLatch latch = new CountDownLatch(1); + instrumentation.getUiAutomation().adoptShellPermissionIdentity( + Manifest.permission.MANAGE_ROLE_HOLDERS, + Manifest.permission.BYPASS_ROLE_QUALIFICATION); + + roleManager.setBypassingRoleQualification(true); + roleManager.addRoleHolderAsUser(role, packageName, + /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user, + mContext.getMainExecutor(), success -> { + if (success) { + latch.countDown(); + } else { + Assert.fail("Couldn't set role for test (failure) " + role); + } + }); + assertWithMessage("Couldn't set role for test (timeout) : " + role) + .that(latch.await(1, TimeUnit.SECONDS)).isTrue(); + block.run(); + + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + roleManager.removeRoleHolderAsUser(role, packageName, + /* flags= */ RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP, user, + mContext.getMainExecutor(), (aBool) -> { + }); + roleManager.setBypassingRoleQualification(false); + instrumentation.getUiAutomation() + .dropShellPermissionIdentity(); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/OWNERS b/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/OWNERS deleted file mode 100644 index bc8efa92c16f..000000000000 --- a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/OWNERS +++ /dev/null @@ -1 +0,0 @@ -include /services/core/java/com/android/server/security/adaptiveauthentication/OWNERS
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationServiceTest.java b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java index 154494a13072..2238a1be97a1 100644 --- a/services/tests/servicestests/src/com/android/server/security/adaptiveauthentication/AdaptiveAuthenticationServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/AuthenticationPolicyServiceTest.java @@ -14,14 +14,14 @@ * limitations under the License. */ -package com.android.server.security.adaptiveauthentication; +package com.android.server.security.authenticationpolicy; import static android.adaptiveauth.Flags.FLAG_ENABLE_ADAPTIVE_AUTH; import static android.adaptiveauth.Flags.FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS; import static android.security.Flags.FLAG_REPORT_PRIMARY_AUTH_ATTEMPTS; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST; -import static com.android.server.security.adaptiveauthentication.AdaptiveAuthenticationService.MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; +import static com.android.server.security.authenticationpolicy.AuthenticationPolicyService.MAX_ALLOWED_FAILED_AUTH_ATTEMPTS; import static org.junit.Assert.assertEquals; import static org.junit.Assume.assumeTrue; @@ -66,12 +66,12 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** - * atest FrameworksServicesTests:AdaptiveAuthenticationServiceTest + * atest FrameworksServicesTests:AuthenticationPolicyServiceTest */ @Presubmit @SmallTest @RunWith(AndroidJUnit4.class) -public class AdaptiveAuthenticationServiceTest { +public class AuthenticationPolicyServiceTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); @@ -81,7 +81,7 @@ public class AdaptiveAuthenticationServiceTest { private static final int REASON_UNKNOWN = 0; // BiometricRequestConstants.RequestReason private Context mContext; - private AdaptiveAuthenticationService mAdaptiveAuthenticationService; + private AuthenticationPolicyService mAuthenticationPolicyService; @Mock LockPatternUtils mLockPatternUtils; @@ -124,9 +124,9 @@ public class AdaptiveAuthenticationServiceTest { LocalServices.removeServiceForTest(UserManagerInternal.class); LocalServices.addService(UserManagerInternal.class, mUserManager); - mAdaptiveAuthenticationService = new AdaptiveAuthenticationService( + mAuthenticationPolicyService = new AuthenticationPolicyService( mContext, mLockPatternUtils); - mAdaptiveAuthenticationService.init(); + mAuthenticationPolicyService.init(); verify(mLockSettings).registerLockSettingsStateListener( mLockSettingsStateListenerCaptor.capture()); @@ -318,13 +318,13 @@ public class AdaptiveAuthenticationServiceTest { private void verifyNotLockDevice(int expectedCntFailedAttempts, int userId) { assertEquals(expectedCntFailedAttempts, - mAdaptiveAuthenticationService.mFailedAttemptsForUser.get(userId)); + mAuthenticationPolicyService.mFailedAttemptsForUser.get(userId)); verify(mWindowManager, never()).lockNow(); } private void verifyLockDevice(int userId) { assertEquals(MAX_ALLOWED_FAILED_AUTH_ATTEMPTS, - mAdaptiveAuthenticationService.mFailedAttemptsForUser.get(userId)); + mAuthenticationPolicyService.mFailedAttemptsForUser.get(userId)); verify(mLockPatternUtils).requireStrongAuth( eq(SOME_AUTH_REQUIRED_AFTER_ADAPTIVE_AUTH_REQUEST), eq(userId)); // If userId is MANAGED_PROFILE_USER_ID, the StrongAuthFlag of its parent (PRIMARY_USER_ID) diff --git a/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/OWNERS b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/OWNERS new file mode 100644 index 000000000000..4310d1a3a9db --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/security/authenticationpolicy/OWNERS @@ -0,0 +1 @@ +include /services/core/java/com/android/server/security/authenticationpolicy/OWNERS
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt index 79b0623640f6..8290e1cfb9db 100644 --- a/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt +++ b/services/tests/servicestests/src/com/android/server/supervision/SupervisionServiceTest.kt @@ -20,7 +20,7 @@ import android.app.admin.DevicePolicyManagerInternal import android.content.ComponentName import android.content.Context import android.content.pm.UserInfo -import android.os.Bundle +import android.os.PersistableBundle import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.DeviceFlagsValueProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -139,7 +139,7 @@ class SupervisionServiceTest { assertThat(userData.supervisionLockScreenEnabled).isFalse() assertThat(userData.supervisionLockScreenOptions).isNull() - service.mInternal.setSupervisionLockscreenEnabledForUser(USER_ID, true, Bundle()) + service.mInternal.setSupervisionLockscreenEnabledForUser(USER_ID, true, PersistableBundle()) userData = service.getUserDataLocked(USER_ID) assertThat(userData.supervisionLockScreenEnabled).isTrue() assertThat(userData.supervisionLockScreenOptions).isNotNull() diff --git a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java index cc0286508cdc..6af65423415b 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/GroupHelperTest.java @@ -84,7 +84,9 @@ import androidx.test.filters.SmallTest; import com.android.internal.R; import com.android.server.UiServiceTestCase; import com.android.server.notification.GroupHelper.CachedSummary; +import com.android.server.notification.GroupHelper.FullyQualifiedGroupKey; import com.android.server.notification.GroupHelper.NotificationAttributes; +import com.android.server.notification.GroupHelper.NotificationSectioner; import org.junit.Before; import org.junit.Rule; @@ -2298,6 +2300,7 @@ public class GroupHelperTest extends UiServiceTestCase { final String pkg = "package"; final String expectedGroupKey_alerting = GroupHelper.getFullAggregateGroupKey(pkg, AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier()); + final int numNotifications = 2 * AUTOGROUP_AT_COUNT; int numNotificationChannel1 = 0; final NotificationChannel channel1 = new NotificationChannel("TEST_CHANNEL_ID1", "TEST_CHANNEL_ID1", IMPORTANCE_DEFAULT); @@ -2307,7 +2310,7 @@ public class GroupHelperTest extends UiServiceTestCase { final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>(); // Post notifications with different channels that autogroup within the same section NotificationRecord r; - for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { + for (int i = 0; i < numNotifications; i++) { if (i % 2 == 0) { r = getNotificationRecord(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "testGrp " + i, false, channel1); @@ -2324,12 +2327,12 @@ public class GroupHelperTest extends UiServiceTestCase { "TEST_CHANNEL_ID1"); verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_alerting), anyInt(), eq(expectedSummaryAttr)); - verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(), + verify(mCallback, times(numNotifications)).addAutoGroup(anyString(), eq(expectedGroupKey_alerting), eq(true)); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); - verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), - any()); + verify(mCallback, times(numNotifications - AUTOGROUP_AT_COUNT)).updateAutogroupSummary( + anyInt(), anyString(), anyString(), any()); Mockito.reset(mCallback); // Update channel1's importance @@ -2375,7 +2378,7 @@ public class GroupHelperTest extends UiServiceTestCase { final List<NotificationRecord> notificationList = new ArrayList<>(); final String pkg = "package"; final int summaryId = 0; - final int numChildNotif = 4; + final int numChildNotif = 2 * AUTOGROUP_AT_COUNT; // Create an app-provided group: summary + child notifications final NotificationChannel channel1 = new NotificationChannel("TEST_CHANNEL_ID1", @@ -2435,8 +2438,8 @@ public class GroupHelperTest extends UiServiceTestCase { eq(expectedGroupKey_social), eq(true)); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); - verify(mCallback, times(numChildNotif / 2)).updateAutogroupSummary(anyInt(), anyString(), - anyString(), any()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), + any()); verify(mCallback, times(numChildNotif)).removeAppProvidedSummaryOnClassification( anyString(), eq(originalAppGroupKey)); } @@ -2513,9 +2516,10 @@ public class GroupHelperTest extends UiServiceTestCase { final List<NotificationRecord> notificationList = new ArrayList<>(); final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>(); final String pkg = "package"; + final int numChildNotifications = AUTOGROUP_AT_COUNT; // Post singleton groups, above forced group limit - for (int i = 0; i < AUTOGROUP_SINGLETONS_AT_COUNT; i++) { + for (int i = 0; i < numChildNotifications; i++) { NotificationRecord summary = getNotificationRecord(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "testGrp " + i, true); notificationList.add(summary); @@ -2545,13 +2549,13 @@ public class GroupHelperTest extends UiServiceTestCase { // Check that notifications are forced grouped and app-provided summaries are canceled verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social)); - verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(), + verify(mCallback, times(numChildNotifications)).addAutoGroup(anyString(), eq(expectedGroupKey_social), eq(true)); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); - verify(mCallback, times(1)).updateAutogroupSummary(anyInt(), anyString(), anyString(), + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), any()); - verify(mCallback, times(2)).removeAppProvidedSummaryOnClassification( + verify(mCallback, times(numChildNotifications)).removeAppProvidedSummaryOnClassification( anyString(), anyString()); // Adjust group key and cancel summaries @@ -2593,14 +2597,16 @@ public class GroupHelperTest extends UiServiceTestCase { AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier()); String expectedTriggeringKey = null; // Post singleton groups, above forced group limit - for (int i = 0; i < AUTOGROUP_SINGLETONS_AT_COUNT; i++) { + for (int i = 0; i < AUTOGROUP_AT_COUNT; i++) { NotificationRecord summary = getNotificationRecord(pkg, i, String.valueOf(i), UserHandle.SYSTEM, "testGrp " + i, true); notificationList.add(summary); NotificationRecord child = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42), UserHandle.SYSTEM, "testGrp " + i, false); notificationList.add(child); - expectedTriggeringKey = child.getKey(); + if (i == AUTOGROUP_SINGLETONS_AT_COUNT - 1) { + expectedTriggeringKey = child.getKey(); + } summaryByGroup.put(summary.getGroupKey(), summary); mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup); summary.isCanceled = true; // simulate removing the app summary @@ -2611,14 +2617,8 @@ public class GroupHelperTest extends UiServiceTestCase { verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), eq(expectedTriggeringKey), eq(expectedGroupKey_alerting), anyInt(), eq(getNotificationAttributes(BASE_FLAGS))); - verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(), - eq(expectedGroupKey_alerting), eq(true)); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); - verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), - any()); - verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).removeAppProvidedSummary( - anyString()); assertThat(mGroupHelper.findCanceledSummary(pkg, String.valueOf(0), 0, UserHandle.SYSTEM.getIdentifier())).isNotNull(); assertThat(mGroupHelper.findCanceledSummary(pkg, String.valueOf(1), 1, @@ -2645,12 +2645,12 @@ public class GroupHelperTest extends UiServiceTestCase { // Check that all notifications are moved to the social section group verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social)); - verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).addAutoGroup(anyString(), + verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(), eq(expectedGroupKey_social), eq(true)); // Check that the alerting section group is removed verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg), eq(expectedGroupKey_alerting)); - verify(mCallback, times(AUTOGROUP_SINGLETONS_AT_COUNT)).updateAutogroupSummary(anyInt(), + verify(mCallback, times(AUTOGROUP_AT_COUNT - 1)).updateAutogroupSummary(anyInt(), anyString(), anyString(), any()); } @@ -2666,7 +2666,7 @@ public class GroupHelperTest extends UiServiceTestCase { final String pkg = "package"; final int summaryId = 0; - final int numChildren = 3; + final int numChildren = AUTOGROUP_AT_COUNT; // Post a regular/valid group: summary + notifications NotificationRecord summary = getNotificationRecord(pkg, summaryId, String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true); @@ -2706,13 +2706,211 @@ public class GroupHelperTest extends UiServiceTestCase { eq(true)); verify(mCallback, never()).removeAutoGroup(anyString()); verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); - verify(mCallback, times(numChildren - 1)).updateAutogroupSummary(anyInt(), anyString(), - anyString(), any()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), + any()); verify(mCallback, times(numChildren)).removeAppProvidedSummaryOnClassification(anyString(), anyString()); } @Test + @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + FLAG_NOTIFICATION_CLASSIFICATION}) + public void testUnbundleNotification_originalSummaryMissing_autogroupInNewSection() { + // Check that unbundled notifications are moved to the original section and aggregated + // with existing autogrouped notifications + final List<NotificationRecord> notificationList = new ArrayList<>(); + final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>(); + final String pkg = "package"; + + final int summaryId = 0; + final int numChildren = AUTOGROUP_AT_COUNT - 1; + // Post a regular/valid group: summary + notifications (one less than autogroup limit) + NotificationRecord summary = getNotificationRecord(pkg, summaryId, + String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true); + notificationList.add(summary); + summaryByGroup.put(summary.getGroupKey(), summary); + final String originalAppGroupKey = summary.getGroupKey(); + final NotificationChannel originalChannel = summary.getChannel(); + for (int i = 0; i < numChildren; i++) { + NotificationRecord child = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42), + UserHandle.SYSTEM, "testGrp", false); + notificationList.add(child); + mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup); + } + + // Classify/bundle all child notifications: original group & summary is removed + final NotificationChannel socialChannel = new NotificationChannel( + NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID, + IMPORTANCE_DEFAULT); + for (NotificationRecord record: notificationList) { + if (record.getOriginalGroupKey().contains("testGrp") + && record.getNotification().isGroupChild()) { + record.updateNotificationChannel(socialChannel); + mGroupHelper.onChannelUpdated(record); + } + } + + // Check that no autogroup summaries were created for the social section + verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(), + anyString(), anyInt(), any()); + verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean()); + verify(mCallback, never()).removeAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), + any()); + verify(mCallback, times(numChildren)).removeAppProvidedSummaryOnClassification( + anyString(), eq(originalAppGroupKey)); + + // Cancel summary + summary.isCanceled = true; + summaryByGroup.clear(); + notificationList.remove(summary); + + // Add 1 ungrouped notification in the original section + NotificationRecord ungroupedNotification = getNotificationRecord(pkg, 4242, + String.valueOf(4242), UserHandle.SYSTEM); + notificationList.add(ungroupedNotification); + mGroupHelper.onNotificationPosted(ungroupedNotification, false); + + // Unbundle the bundled notifications => notifications are moved back to the original group + // and an aggregate group is created because autogroup limit is reached + reset(mCallback); + for (NotificationRecord record: notificationList) { + if (record.getNotification().isGroupChild() + && record.getOriginalGroupKey().contains("testGrp") + && NotificationChannel.SYSTEM_RESERVED_IDS.contains( + record.getChannel().getId())) { + record.updateNotificationChannel(originalChannel); + mGroupHelper.onNotificationUnbundled(record, false); + } + } + + // Check that a new aggregate group is created + final String expectedGroupKey_alerting = GroupHelper.getFullAggregateGroupKey(pkg, + AGGREGATE_GROUP_KEY + "AlertingSection", UserHandle.SYSTEM.getIdentifier()); + verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), + eq(expectedGroupKey_alerting), anyInt(), any()); + verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(), + eq(expectedGroupKey_alerting), eq(true)); + verify(mCallback, never()).removeAutoGroup(anyString()); + verify(mCallback, times(numChildren)).removeAutoGroupSummary(anyInt(), anyString(), + anyString()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), + any()); + } + + @Test + @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, + FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, + FLAG_NOTIFICATION_CLASSIFICATION}) + public void testUnbundleNotification_originalSummaryExists() { + // Check that unbundled notifications are moved to the original section and original group + // when the original summary is still present + final List<NotificationRecord> notificationList = new ArrayList<>(); + final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>(); + final String pkg = "package"; + + final int summaryId = 0; + final int numChildren = AUTOGROUP_AT_COUNT + 1; + // Post a regular/valid group: summary + notifications + NotificationRecord summary = getNotificationRecord(pkg, summaryId, + String.valueOf(summaryId), UserHandle.SYSTEM, "testGrp", true); + notificationList.add(summary); + summaryByGroup.put(summary.getGroupKey(), summary); + final String originalAppGroupKey = summary.getGroupKey(); + final NotificationChannel originalChannel = summary.getChannel(); + for (int i = 0; i < numChildren; i++) { + NotificationRecord child = getNotificationRecord(pkg, i + 42, String.valueOf(i + 42), + UserHandle.SYSTEM, "testGrp", false); + notificationList.add(child); + mGroupHelper.onNotificationPostedWithDelay(child, notificationList, summaryByGroup); + } + + // Classify/bundle child notifications: all except one, to keep the original group + final NotificationChannel socialChannel = new NotificationChannel( + NotificationChannel.SOCIAL_MEDIA_ID, NotificationChannel.SOCIAL_MEDIA_ID, + IMPORTANCE_DEFAULT); + final String expectedGroupKey_social = GroupHelper.getFullAggregateGroupKey(pkg, + AGGREGATE_GROUP_KEY + "SocialSection", UserHandle.SYSTEM.getIdentifier()); + final NotificationAttributes expectedSummaryAttr_social = new NotificationAttributes( + BASE_FLAGS, mSmallIcon, COLOR_DEFAULT, DEFAULT_VISIBILITY, DEFAULT_GROUP_ALERT, + NotificationChannel.SOCIAL_MEDIA_ID); + int numChildrenBundled = 0; + for (NotificationRecord record: notificationList) { + if (record.getOriginalGroupKey().contains("testGrp") + && record.getNotification().isGroupChild()) { + record.updateNotificationChannel(socialChannel); + mGroupHelper.onChannelUpdated(record); + numChildrenBundled++; + if (numChildrenBundled == AUTOGROUP_AT_COUNT) { + break; + } + } + } + + // Check that 1 autogroup summaries were created for the social section + verify(mCallback, times(1)).addAutoGroupSummary(anyInt(), eq(pkg), anyString(), + eq(expectedGroupKey_social), anyInt(), eq(expectedSummaryAttr_social)); + verify(mCallback, times(AUTOGROUP_AT_COUNT)).addAutoGroup(anyString(), + eq(expectedGroupKey_social), eq(true)); + verify(mCallback, never()).removeAutoGroup(anyString()); + verify(mCallback, never()).removeAutoGroupSummary(anyInt(), anyString(), anyString()); + verify(mCallback, never()).updateAutogroupSummary(anyInt(), anyString(), anyString(), + any()); + verify(mCallback, times(AUTOGROUP_AT_COUNT)).removeAppProvidedSummaryOnClassification( + anyString(), eq(originalAppGroupKey)); + + // Adjust group key and cancel summaries + for (NotificationRecord record: notificationList) { + if (record.getNotification().isGroupSummary()) { + record.isCanceled = true; + } else if (record.getOriginalGroupKey().contains("testGrp") + && NotificationChannel.SYSTEM_RESERVED_IDS.contains( + record.getChannel().getId())) { + record.setOverrideGroupKey(expectedGroupKey_social); + } + } + + // Add 1 ungrouped notification in the original section + NotificationRecord ungroupedNotification = getNotificationRecord(pkg, 4242, + String.valueOf(4242), UserHandle.SYSTEM); + notificationList.add(ungroupedNotification); + mGroupHelper.onNotificationPosted(ungroupedNotification, false); + + // Unbundle the bundled notifications => social section summary is destroyed + // and notifications are moved back to the original group + reset(mCallback); + for (NotificationRecord record: notificationList) { + if (record.getNotification().isGroupChild() + && record.getOriginalGroupKey().contains("testGrp") + && NotificationChannel.SYSTEM_RESERVED_IDS.contains( + record.getChannel().getId())) { + record.updateNotificationChannel(originalChannel); + mGroupHelper.onNotificationUnbundled(record, true); + } + } + + // Check that the autogroup summary for the social section was removed + // and that no new autogroup summaries were created + verify(mCallback, never()).addAutoGroupSummary(anyInt(), anyString(), anyString(), + anyString(), anyInt(), any()); + verify(mCallback, never()).addAutoGroup(anyString(), anyString(), anyBoolean()); + verify(mCallback, never()).removeAutoGroup(anyString()); + verify(mCallback, times(1)).removeAutoGroupSummary(anyInt(), eq(pkg), + eq(expectedGroupKey_social)); + verify(mCallback, times(AUTOGROUP_AT_COUNT - 1)).updateAutogroupSummary(anyInt(), eq(pkg), + eq(expectedGroupKey_social), any()); + + for (NotificationRecord record: notificationList) { + if (record.getNotification().isGroupChild() + && record.getOriginalGroupKey().contains("testGrp")) { + assertThat(record.getSbn().getOverrideGroupKey()).isNull(); + } + } + } + + @Test @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) public void testMoveAggregateGroups_updateChannel_groupsUngrouped() { final String pkg = "package"; @@ -3059,6 +3257,120 @@ public class GroupHelperTest extends UiServiceTestCase { @Test @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS) + public void testNonGroupableChildren_singletonGroups_disableConversations() { + // Check that singleton groups with children that are not groupable, is not grouped + // Even though the group summary is a regular (alerting) notification, the children are + // conversations => the group should not be forced grouped. + final List<NotificationRecord> notificationList = new ArrayList<>(); + final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>(); + final String pkg = "package"; + + // Trigger notification, ungrouped + final int triggerId = 1; + NotificationRecord triggerNotification = getNotificationRecord(pkg, triggerId, + String.valueOf(triggerId), UserHandle.SYSTEM); + notificationList.add(triggerNotification); + final NotificationSectioner triggerSection = GroupHelper.getSection(triggerNotification); + final FullyQualifiedGroupKey triggerFullAggregateGroupKey = new FullyQualifiedGroupKey( + triggerNotification.getUserId(), triggerNotification.getSbn().getPackageName(), + triggerSection); + + // Add singleton group with alerting child + final String groupName_valid = "testGrp_valid"; + final int summaryId_valid = 0; + NotificationRecord summary = getNotificationRecord(pkg, summaryId_valid, + String.valueOf(summaryId_valid), UserHandle.SYSTEM, groupName_valid, true); + notificationList.add(summary); + summaryByGroup.put(summary.getGroupKey(), summary); + final String groupKey_valid = summary.getGroupKey(); + NotificationRecord child = getNotificationRecord(pkg, summaryId_valid + 42, + String.valueOf(summaryId_valid + 42), UserHandle.SYSTEM, groupName_valid, false); + notificationList.add(child); + + // Add singleton group with conversation child + final String groupName_invalid = "testGrp_invalid"; + final int summaryId_invalid = 100; + summary = getNotificationRecord(pkg, summaryId_invalid, + String.valueOf(summaryId_invalid), UserHandle.SYSTEM, groupName_invalid, true); + notificationList.add(summary); + final String groupKey_invalid = summary.getGroupKey(); + summaryByGroup.put(summary.getGroupKey(), summary); + child = getNotificationRecord(pkg, summaryId_invalid + 42, + String.valueOf(summaryId_invalid + 42), UserHandle.SYSTEM, groupName_invalid, + false); + child = spy(child); + when(child.isConversation()).thenReturn(true); + notificationList.add(child); + + // Check that the invalid group will not be force grouped + final ArrayMap<String, NotificationRecord> sparseGroups = mGroupHelper.getSparseGroups( + triggerFullAggregateGroupKey, notificationList, summaryByGroup, triggerSection); + assertThat(sparseGroups).containsKey(groupKey_valid); + assertThat(sparseGroups).doesNotContainKey(groupKey_invalid); + } + + @Test + @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS}) + public void testNonGroupableChildren_singletonGroups_enableConversations() { + // Check that singleton groups with children that are not groupable, is not grouped + // Conversations are groupable (FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS is enabled) + // The invalid group is the alerting notifications: because the triggering notifications' + // section is Conversations, so the alerting group should be skipped. + final List<NotificationRecord> notificationList = new ArrayList<>(); + final ArrayMap<String, NotificationRecord> summaryByGroup = new ArrayMap<>(); + final String pkg = "package"; + + // Trigger notification, ungrouped conversation + final int triggerId = 1; + NotificationRecord triggerNotification = getNotificationRecord(pkg, triggerId, + String.valueOf(triggerId), UserHandle.SYSTEM); + triggerNotification = spy(triggerNotification); + when(triggerNotification.isConversation()).thenReturn(true); + notificationList.add(triggerNotification); + final NotificationSectioner triggerSection = GroupHelper.getSection(triggerNotification); + final FullyQualifiedGroupKey triggerFullAggregateGroupKey = new FullyQualifiedGroupKey( + triggerNotification.getUserId(), triggerNotification.getSbn().getPackageName(), + triggerSection); + + // Add singleton group with conversation child + final String groupName_valid = "testGrp_valid"; + final int summaryId_valid = 0; + NotificationRecord summary = getNotificationRecord(pkg, summaryId_valid, + String.valueOf(summaryId_valid), UserHandle.SYSTEM, groupName_valid, true); + summary = spy(summary); + when(summary.isConversation()).thenReturn(true); + notificationList.add(summary); + summaryByGroup.put(summary.getGroupKey(), summary); + final String groupKey_valid = summary.getGroupKey(); + NotificationRecord child = getNotificationRecord(pkg, summaryId_valid + 42, + String.valueOf(summaryId_valid + 42), UserHandle.SYSTEM, groupName_valid, false); + child = spy(child); + when(child.isConversation()).thenReturn(true); + notificationList.add(child); + + // Add singleton group with non-conversation child + final String groupName_invalid = "testGrp_invalid"; + final int summaryId_invalid = 100; + summary = getNotificationRecord(pkg, summaryId_invalid, + String.valueOf(summaryId_invalid), UserHandle.SYSTEM, groupName_invalid, true); + notificationList.add(summary); + final String groupKey_invalid = summary.getGroupKey(); + summaryByGroup.put(summary.getGroupKey(), summary); + child = getNotificationRecord(pkg, summaryId_invalid + 42, + String.valueOf(summaryId_invalid + 42), UserHandle.SYSTEM, groupName_invalid, + false); + notificationList.add(child); + + // Check that the invalid group will not be force grouped + final ArrayMap<String, NotificationRecord> sparseGroups = mGroupHelper.getSparseGroups( + triggerFullAggregateGroupKey, notificationList, summaryByGroup, triggerSection); + assertThat(sparseGroups).containsKey(groupKey_valid); + assertThat(sparseGroups).doesNotContainKey(groupKey_invalid); + } + + @Test + @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) + @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUP_CONVERSATIONS) public void testNonGroupableNotifications() { // Check that there is no valid section for: conversations, calls, foreground services NotificationRecord notification_conversation = mock(NotificationRecord.class); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 020670dc0f0a..bf61d06a80a7 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -72,6 +72,7 @@ import static android.service.notification.ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_ACTIVATE; import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_DEACTIVATE; import static android.service.notification.ZenModeConfig.ZenRule.OVERRIDE_NONE; +import static android.service.notification.ZenModeConfig.implicitRuleId; import static android.service.notification.ZenPolicy.PEOPLE_TYPE_CONTACTS; import static android.service.notification.ZenPolicy.PEOPLE_TYPE_NONE; import static android.service.notification.ZenPolicy.PEOPLE_TYPE_STARRED; @@ -201,9 +202,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.xmlpull.v1.XmlPullParserException; -import platform.test.runner.parameterized.ParameterizedAndroidJunit4; -import platform.test.runner.parameterized.Parameters; - import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; @@ -223,6 +221,9 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import platform.test.runner.parameterized.ParameterizedAndroidJunit4; +import platform.test.runner.parameterized.Parameters; + @SmallTest @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service. @RunWith(ParameterizedAndroidJunit4.class) @@ -7067,6 +7068,50 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertThat(getZenRule(ruleId).getConditionOverride()).isEqualTo(OVERRIDE_NONE); } + @Test + @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI}) + public void setAutomaticZenRuleState_implicitRuleManualActivation_doesNotUseOverride() { + mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS, + PERMISSION_GRANTED); // So that canManageAZR succeeds. + mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME, + CUSTOM_PKG_UID, ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME, + CUSTOM_PKG_UID, ZEN_MODE_OFF); + ZenRule implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME)); + assertThat(implicitRule.isActive()).isFalse(); + + mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id, + new Condition(implicitRule.conditionId, "on!", STATE_TRUE, SOURCE_USER_ACTION), + ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID); + + implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME)); + assertThat(mZenModeHelper.getAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id)) + .isEqualTo(STATE_TRUE); + assertThat(implicitRule.isActive()).isTrue(); + assertThat(implicitRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE); + } + + @Test + @EnableFlags({FLAG_MODES_API, FLAG_MODES_UI}) + public void setAutomaticZenRuleState_implicitRuleManualDeactivation_doesNotUseOverride() { + mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS, + PERMISSION_GRANTED); // So that canManageAZR succeeds. + mZenModeHelper.applyGlobalZenModeAsImplicitZenRule(UserHandle.CURRENT, CUSTOM_PKG_NAME, + CUSTOM_PKG_UID, ZEN_MODE_IMPORTANT_INTERRUPTIONS); + ZenRule implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME)); + assertThat(implicitRule.isActive()).isTrue(); + + mZenModeHelper.setAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id, + new Condition(implicitRule.conditionId, "off!", STATE_FALSE, SOURCE_USER_ACTION), + ORIGIN_USER_IN_SYSTEMUI, SYSTEM_UID); + + implicitRule = getZenRule(implicitRuleId(CUSTOM_PKG_NAME)); + assertThat(mZenModeHelper.getAutomaticZenRuleState(UserHandle.CURRENT, implicitRule.id)) + .isEqualTo(STATE_FALSE); + assertThat(implicitRule.isActive()).isFalse(); + assertThat(implicitRule.getConditionOverride()).isEqualTo(OVERRIDE_NONE); + } + private ZenRule getZenRule(String ruleId) { return checkNotNull(mZenModeHelper.mConfig.automaticRules.get(ruleId), "Didn't find rule with id %s", ruleId); diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java index 3c2f9616bec5..eb44daabd002 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibrationThreadTest.java @@ -747,6 +747,23 @@ public class VibrationThreadTest { } @Test + @DisableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY) + public void vibrate_singleVibratorComposedAndNoCapability_triggersHalAndReturnsUnsupported() { + VibrationEffect effect = VibrationEffect.startComposition() + .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f) + .compose(); + HalVibration vibration = startThreadAndDispatcher(effect); + waitForCompletion(); + + verify(mManagerHooks).noteVibratorOn(eq(UID), eq(0L)); + verify(mManagerHooks, never()).noteVibratorOff(eq(UID)); + verify(mControllerCallbacks, never()).onComplete(eq(VIBRATOR_ID), eq(vibration.id)); + verifyCallbacksTriggered(vibration, Status.IGNORED_UNSUPPORTED); + assertTrue(mVibratorProviders.get(VIBRATOR_ID).getEffectSegments(vibration.id).isEmpty()); + } + + @Test + @EnableFlags(Flags.FLAG_PRIMITIVE_COMPOSITION_ABSOLUTE_DELAY) public void vibrate_singleVibratorComposedAndNoCapability_ignoresVibration() { VibrationEffect effect = VibrationEffect.startComposition() .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f) @@ -887,7 +904,7 @@ public class VibrationThreadTest { fakeVibrator.setMaxEnvelopeEffectSize(10); fakeVibrator.setMinEnvelopeEffectControlPointDurationMillis(20); - VibrationEffect effect = VibrationEffect.startWaveformEnvelope() + VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder() .addControlPoint(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30) .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 20) @@ -922,12 +939,14 @@ public class VibrationThreadTest { fakeVibrator.setMaxEnvelopeEffectSize(10); fakeVibrator.setMinEnvelopeEffectControlPointDurationMillis(20); - VibrationEffect effect = VibrationEffect.startWaveformEnvelope(/*initialFrequency=*/ 30) + VibrationEffect effect = new VibrationEffect.WaveformEnvelopeBuilder() + .setInitialFrequencyHz(/*initialFrequencyHz=*/ 30) .addControlPoint(/*amplitude=*/ 0.1f, /*frequencyHz=*/ 60f, /*timeMillis=*/ 20) .addControlPoint(/*amplitude=*/ 0.3f, /*frequencyHz=*/ 100f, /*timeMillis=*/ 30) .addControlPoint(/*amplitude=*/ 0.4f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 20) .addControlPoint(/*amplitude=*/ 0.0f, /*frequencyHz=*/ 120f, /*timeMillis=*/ 30) .build(); + HalVibration vibration = startThreadAndDispatcher(effect); waitForCompletion(); diff --git a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java index 5f76d6815cb8..ec83e990a70d 100644 --- a/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java +++ b/services/tests/vibrator/src/com/android/server/vibrator/VibratorManagerServiceTest.java @@ -2865,7 +2865,7 @@ public class VibratorManagerServiceTest { mTestLooper.dispatchAll(); assertThat(session.getStatus()).isEqualTo(Status.IGNORED_UNSUPPORTED); - verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 3})); + verify(mNativeWrapperMock, never()).startSession(anyLong(), any(int[].class)); verify(callback, never()).onStarted(any(IVibrationSession.class)); verify(callback, never()).onFinishing(); verify(callback) @@ -2889,6 +2889,7 @@ public class VibratorManagerServiceTest { verify(callback).onStarted(captor.capture()); captor.getValue().finishSession(); + mTestLooper.dispatchAll(); // Session not ended until HAL callback. assertThat(session.getStatus()).isEqualTo(Status.RUNNING); @@ -3139,6 +3140,224 @@ public class VibratorManagerServiceTest { } @Test + @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS) + public void vibrateInSession_afterCancel_vibrationIgnored() throws Exception { + mockCapabilities(IVibratorManager.CAP_START_SESSIONS); + mockVibrators(1, 2); + FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1); + fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + VibratorManagerService service = createSystemReadyService(); + int sessionFinishDelayMs = 200; + IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs); + + VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2); + mTestLooper.dispatchAll(); + + verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2})); + ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class); + verify(callback).onStarted(captor.capture()); + + IVibrationSession startedSession = captor.getValue(); + startedSession.cancelSession(); + startedSession.vibrate( + CombinedVibration.createParallel(VibrationEffect.createOneShot(10, 255)), + "reason"); + + // VibrationThread will never start this vibration. + assertFalse(waitUntil(s -> !fakeVibrator1.getAmplitudes().isEmpty(), service, + TEST_TIMEOUT_MILLIS)); + + // Dispatch HAL callbacks. + mTestLooper.moveTimeForward(sessionFinishDelayMs); + mTestLooper.dispatchAll(); + + assertThat(session.getStatus()).isEqualTo(Status.CANCELLED_BY_USER); + verify(callback).onFinishing(); + verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_CANCELED)); + } + + @Test + @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS) + public void vibrateInSession_afterFinish_vibrationIgnored() throws Exception { + mockCapabilities(IVibratorManager.CAP_START_SESSIONS); + mockVibrators(1, 2); + FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1); + fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + VibratorManagerService service = createSystemReadyService(); + int sessionFinishDelayMs = 200; + IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs); + + VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2); + mTestLooper.dispatchAll(); + + verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2})); + ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class); + verify(callback).onStarted(captor.capture()); + + IVibrationSession startedSession = captor.getValue(); + startedSession.finishSession(); + mTestLooper.dispatchAll(); + + startedSession.vibrate( + CombinedVibration.createParallel(VibrationEffect.createOneShot(10, 255)), + "reason"); + + // Session not ended until HAL callback. + assertThat(session.getStatus()).isEqualTo(Status.RUNNING); + + // VibrationThread will never start this vibration. + assertFalse(waitUntil(s -> !fakeVibrator1.getAmplitudes().isEmpty(), service, + TEST_TIMEOUT_MILLIS)); + + // Dispatch HAL callbacks. + mTestLooper.moveTimeForward(sessionFinishDelayMs); + mTestLooper.dispatchAll(); + + assertThat(session.getStatus()).isEqualTo(Status.FINISHED); + verify(callback).onFinishing(); + verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS)); + } + + @Test + @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS) + public void vibrateInSession_repeatingVibration_vibrationIgnored() throws Exception { + mockCapabilities(IVibratorManager.CAP_START_SESSIONS); + mockVibrators(1, 2); + FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1); + fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + VibratorManagerService service = createSystemReadyService(); + int sessionFinishDelayMs = 200; + IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs); + + VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2); + mTestLooper.dispatchAll(); + + verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2})); + ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class); + verify(callback).onStarted(captor.capture()); + + IVibrationSession startedSession = captor.getValue(); + startedSession.vibrate( + CombinedVibration.createParallel( + VibrationEffect.createWaveform(new long[]{ 10, 10, 10, 10}, 0)), + "reason"); + + // VibrationThread will never start this vibration. + assertFalse(waitUntil(s -> !fakeVibrator1.getAmplitudes().isEmpty(), service, + TEST_TIMEOUT_MILLIS)); + + startedSession.finishSession(); + mTestLooper.dispatchAll(); + + // Dispatch HAL callbacks. + mTestLooper.moveTimeForward(sessionFinishDelayMs); + mTestLooper.dispatchAll(); + + assertThat(session.getStatus()).isEqualTo(Status.FINISHED); + assertThat(service.isVibrating(1)).isFalse(); + assertThat(service.isVibrating(2)).isFalse(); + verify(callback).onFinishing(); + verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS)); + } + + @Test + @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS) + public void vibrateInSession_singleVibration_playsAllVibrateCommands() throws Exception { + mockCapabilities(IVibratorManager.CAP_START_SESSIONS); + mockVibrators(1, 2); + FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1); + fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + FakeVibratorControllerProvider fakeVibrator2 = mVibratorProviders.get(1); + fakeVibrator2.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + VibratorManagerService service = createSystemReadyService(); + int sessionFinishDelayMs = 200; + IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs); + + VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2); + mTestLooper.dispatchAll(); + + verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2})); + ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class); + verify(callback).onStarted(captor.capture()); + + IVibrationSession startedSession = captor.getValue(); + startedSession.vibrate( + CombinedVibration.createParallel( + VibrationEffect.createWaveform(new long[]{ 10, 10, 10, 10}, -1)), + "reason"); + + // VibrationThread will start this vibration async, so wait until vibration is triggered. + // Vibrators will receive 2 requests for the waveform playback + assertTrue(waitUntil(s -> fakeVibrator1.getAmplitudes().size() == 2, service, + TEST_TIMEOUT_MILLIS)); + assertTrue(waitUntil(s -> fakeVibrator2.getAmplitudes().size() == 2, service, + TEST_TIMEOUT_MILLIS)); + + startedSession.finishSession(); + mTestLooper.dispatchAll(); + + // Dispatch HAL callbacks. + mTestLooper.moveTimeForward(sessionFinishDelayMs); + mTestLooper.dispatchAll(); + + assertThat(session.getStatus()).isEqualTo(Status.FINISHED); + assertThat(service.isVibrating(1)).isFalse(); + assertThat(service.isVibrating(2)).isFalse(); + verify(callback).onFinishing(); + verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS)); + } + + @Test + @EnableFlags(android.os.vibrator.Flags.FLAG_VENDOR_VIBRATION_EFFECTS) + public void vibrateInSession_multipleVibrations_playsAllVibrations() throws Exception { + mockCapabilities(IVibratorManager.CAP_START_SESSIONS); + mockVibrators(1, 2); + FakeVibratorControllerProvider fakeVibrator1 = mVibratorProviders.get(1); + fakeVibrator1.setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL); + VibratorManagerService service = createSystemReadyService(); + int sessionFinishDelayMs = 200; + IVibrationSessionCallback callback = mockSessionCallbacks(sessionFinishDelayMs); + + VendorVibrationSession session = startSession(service, RINGTONE_ATTRS, callback, 1, 2); + mTestLooper.dispatchAll(); + + verify(mNativeWrapperMock).startSession(eq(session.getSessionId()), eq(new int[] {1, 2})); + ArgumentCaptor<IVibrationSession> captor = ArgumentCaptor.forClass(IVibrationSession.class); + verify(callback).onStarted(captor.capture()); + + IVibrationSession startedSession = captor.getValue(); + startedSession.vibrate( + CombinedVibration.createParallel(VibrationEffect.createOneShot(10, 255)), + "reason"); + + // VibrationThread will start this vibration async, so wait until vibration is completed. + assertTrue(waitUntil(s -> fakeVibrator1.getAmplitudes().size() == 1, service, + TEST_TIMEOUT_MILLIS)); + assertTrue(waitUntil(s -> !session.getVibrations().isEmpty(), service, + TEST_TIMEOUT_MILLIS)); + + startedSession.vibrate( + CombinedVibration.createParallel(VibrationEffect.createOneShot(20, 255)), + "reason"); + + assertTrue(waitUntil(s -> fakeVibrator1.getAmplitudes().size() == 2, service, + TEST_TIMEOUT_MILLIS)); + + startedSession.finishSession(); + mTestLooper.dispatchAll(); + + // Dispatch HAL callbacks. + mTestLooper.moveTimeForward(sessionFinishDelayMs); + mTestLooper.dispatchAll(); + + assertThat(session.getStatus()).isEqualTo(Status.FINISHED); + assertThat(service.isVibrating(1)).isFalse(); + assertThat(service.isVibrating(2)).isFalse(); + verify(callback).onFinishing(); + verify(callback).onFinished(eq(android.os.vibrator.VendorVibrationSession.STATUS_SUCCESS)); + } + + @Test public void frameworkStats_externalVibration_reportsAllMetrics() throws Exception { mockVibrators(1); mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_EXTERNAL_CONTROL); diff --git a/services/tests/wmtests/res/xml/bookmarks.xml b/services/tests/wmtests/res/xml/bookmarks.xml index 197b36623fff..787f4e85c012 100644 --- a/services/tests/wmtests/res/xml/bookmarks.xml +++ b/services/tests/wmtests/res/xml/bookmarks.xml @@ -13,60 +13,70 @@ See the License for the specific language governing permissions and limitations under the License. --> -<bookmarks> +<bookmarks xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <!-- the key combinations for the following shortcuts must be in sync with the key combinations sent by the test in ModifierShortcutTests.java --> <bookmark role="android.app.role.BROWSER" - shortcut="b" /> + androidprv:keycode="KEYCODE_B" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CONTACTS" - shortcut="c" /> + androidprv:keycode="KEYCODE_C" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_EMAIL" - shortcut="e" /> + androidprv:keycode="KEYCODE_E" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CALENDAR" - shortcut="k" /> + androidprv:keycode="KEYCODE_K" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_MAPS" - shortcut="m" /> + androidprv:keycode="KEYCODE_M" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_MUSIC" - shortcut="p" /> + androidprv:keycode="KEYCODE_P" + androidprv:modifierState="META" /> <bookmark role="android.app.role.SMS" - shortcut="s" /> + androidprv:keycode="KEYCODE_S" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CALCULATOR" - shortcut="u" /> + androidprv:keycode="KEYCODE_U" + androidprv:modifierState="META" /> <bookmark role="android.app.role.BROWSER" - shortcut="b" - shift="true" /> + androidprv:keycode="KEYCODE_B" + androidprv:modifierState="META|SHIFT" /> <bookmark category="android.intent.category.APP_CONTACTS" - shortcut="c" - shift="true" /> + androidprv:keycode="KEYCODE_C" + androidprv:modifierState="META|SHIFT" /> <bookmark package="com.test" class="com.test.BookmarkTest" - shortcut="j" - shift="true" /> + androidprv:keycode="KEYCODE_J" + androidprv:modifierState="META|SHIFT" /> <!-- The following shortcuts will not be invoked by tests but are here to provide test coverage of parsing the different types of shortcut. --> <bookmark package="com.test" class="com.test.BookmarkTest" - shortcut="j" /> + androidprv:keycode="KEYCODE_J" + androidprv:modifierState="META" /> <bookmark package="com.test2" class="com.test.BookmarkTest" - shortcut="d" /> + androidprv:keycode="KEYCODE_D" + androidprv:modifierState="META" /> <!-- It's intended that this package/class will NOT resolve so we test the resolution @@ -74,6 +84,7 @@ <bookmark package="com.test3" class="com.test.BookmarkTest" - shortcut="f" /> + androidprv:keycode="KEYCODE_F" + androidprv:modifierState="META" /> </bookmarks> diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java index 0575d98b65ec..82a5add407f4 100644 --- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java +++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java @@ -116,6 +116,7 @@ public class ModifierShortcutManagerTests { mModifierShortcutManager = new ModifierShortcutManager( mContext, mHandler, UserHandle.SYSTEM); + mModifierShortcutManager.onSystemReady(); } @Test diff --git a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java index a51ce9951ab4..bc03c233b459 100644 --- a/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java +++ b/services/tests/wmtests/src/com/android/server/policy/TestPhoneWindowManager.java @@ -88,6 +88,7 @@ import android.service.dreams.DreamManagerInternal; import android.telecom.TelecomManager; import android.view.Display; import android.view.InputEvent; +import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.accessibility.AccessibilityManager; import android.view.autofill.AutofillManagerInternal; @@ -270,11 +271,15 @@ class TestPhoneWindowManager { // Return mocked services: LocalServices.getService mMockitoSession = mockitoSession() .mockStatic(LocalServices.class, spyStubOnly) + .mockStatic(KeyCharacterMap.class) .strictness(Strictness.LENIENT) .startMocking(); mPhoneWindowManager = spy(new PhoneWindowManager()); + KeyCharacterMap virtualKcm = mContext.getSystemService(InputManager.class) + .getInputDevice(KeyCharacterMap.VIRTUAL_KEYBOARD).getKeyCharacterMap(); + doReturn(virtualKcm).when(() -> KeyCharacterMap.load(anyInt())); doReturn(mWindowManagerInternal).when( () -> LocalServices.getService(eq(WindowManagerInternal.class))); doReturn(mActivityManagerInternal).when( diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java index 42e31de295d6..817c368745d1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowOrganizerTests.java @@ -82,6 +82,7 @@ import android.graphics.Rect; import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; +import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.util.ArrayMap; @@ -122,6 +123,8 @@ import java.util.function.BiConsumer; * Build/Install/Run: * atest WmTests:WindowOrganizerTests */ + +// TODO revert parts of this set to set the flag to test the behavior @SmallTest @Presubmit @RunWith(WindowTestRunner.class) @@ -1299,6 +1302,7 @@ public class WindowOrganizerTests extends WindowTestsBase { } @Test + @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2) public void testEnterPipParams() { final StubOrganizer o = new StubOrganizer(); mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(o); @@ -1314,6 +1318,7 @@ public class WindowOrganizerTests extends WindowTestsBase { } @Test + @DisableFlags(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2) public void testChangePipParams() { class ChangeSavingOrganizer extends StubOrganizer { RunningTaskInfo mChangedInfo; 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 b737d35c1534..50e0e181cd68 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -71,6 +71,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -84,12 +85,14 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.when; +import android.content.ContentResolver; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Region; +import android.os.Build; import android.os.IBinder; import android.os.InputConfig; import android.os.RemoteException; @@ -97,6 +100,7 @@ import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.annotations.RequiresFlagsEnabled; +import android.provider.Settings; import android.util.ArraySet; import android.util.MergedConfiguration; import android.view.Gravity; @@ -1557,6 +1561,57 @@ public class WindowStateTests extends WindowTestsBase { } @Test + public void testIsSecureLocked_flagSecureSet() { + WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window", + 1 /* ownerId */); + window.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SECURE; + + assertTrue(window.isSecureLocked()); + } + + @Test + public void testIsSecureLocked_flagSecureNotSet() { + WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window", + 1 /* ownerId */); + + assertFalse(window.isSecureLocked()); + } + + @Test + public void testIsSecureLocked_disableSecureWindows() { + assumeTrue(Build.IS_DEBUGGABLE); + + WindowState window = createWindow(null /* parent */, TYPE_APPLICATION, "test-window", + 1 /* ownerId */); + window.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SECURE; + ContentResolver cr = useFakeSettingsProvider(); + + // isSecureLocked should return false when DISABLE_SECURE_WINDOWS is set to 1 + Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "1"); + mWm.mSettingsObserver.onChange(false /* selfChange */, + Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS)); + assertFalse(window.isSecureLocked()); + + // isSecureLocked should return true if DISABLE_SECURE_WINDOWS is set to 0. + Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "0"); + mWm.mSettingsObserver.onChange(false /* selfChange */, + Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS)); + assertTrue(window.isSecureLocked()); + + // Disable secure windows again. + Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, "1"); + mWm.mSettingsObserver.onChange(false /* selfChange */, + Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS)); + assertFalse(window.isSecureLocked()); + + // isSecureLocked should return true if DISABLE_SECURE_WINDOWS is deleted. + Settings.Secure.putString(cr, Settings.Secure.DISABLE_SECURE_WINDOWS, null); + mWm.mSettingsObserver.onChange(false /* selfChange */, + Settings.Secure.getUriFor(Settings.Secure.DISABLE_SECURE_WINDOWS)); + assertTrue(window.isSecureLocked()); + } + + @Test @RequiresFlagsEnabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION) public void testIsSecureLocked_sensitiveContentProtectionManagerEnabled() { String testPackage = "test"; diff --git a/core/java/android/text/ClientFlags.java b/telephony/java/android/telephony/CellularIdentifierDisclosure.aidl index ca887646b3aa..1e41d6e2cc31 100644 --- a/core/java/android/text/ClientFlags.java +++ b/telephony/java/android/telephony/CellularIdentifierDisclosure.aidl @@ -14,16 +14,7 @@ * limitations under the License. */ -package android.text; +/** @hide */ +package android.telephony; -/** - * An aconfig feature flags that can be accessible from application process without - * ContentProvider IPCs. - * - * When you add new flags, you have to add flag string to {@link TextFlags#TEXT_ACONFIGS_FLAGS}. - * - * TODO(nona): Remove this class. - * @hide - */ -public class ClientFlags { -} +parcelable CellularIdentifierDisclosure; diff --git a/telephony/java/android/telephony/CellularIdentifierDisclosure.java b/telephony/java/android/telephony/CellularIdentifierDisclosure.java index 7b2db6d59819..0b6a70feac9d 100644 --- a/telephony/java/android/telephony/CellularIdentifierDisclosure.java +++ b/telephony/java/android/telephony/CellularIdentifierDisclosure.java @@ -16,11 +16,16 @@ package android.telephony; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.telephony.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -31,16 +36,88 @@ import java.util.Objects; * * @hide */ +@SystemApi +@FlaggedApi(Flags.FLAG_CELLULAR_IDENTIFIER_DISCLOSURE_INDICATIONS) public final class CellularIdentifierDisclosure implements Parcelable { private static final String TAG = "CellularIdentifierDisclosure"; + /* Non-access stratum protocol messages */ + /** Unknown */ + public static final int NAS_PROTOCOL_MESSAGE_UNKNOWN = 0; + /** ATTACH REQUESTS. Sample reference: TS 24.301 8.2.4 Applies to 2g, 3g, and 4g networks */ + public static final int NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST = 1; + /** IDENTITY RESPONSE. Sample Reference: TS 24.301 8.2.19. + * Applies to 2g, 3g, 4g, and 5g networks */ + public static final int NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE = 2; + /** DETACH_REQUEST. Sample Reference: TS 24.301 8.2.11. Applies to 2g, 3g, and 4g networks */ + public static final int NAS_PROTOCOL_MESSAGE_DETACH_REQUEST = 3; + /** TRACKING AREA UPDATE (TAU) REQUEST. Sample Reference: 3GPP TS 24.301 8.2.29. + * Note: that per the spec, only temporary IDs should be sent in the TAU Request, but since the + * EPS Mobile Identity field supports IMSIs, this is included as an extra safety measure to + * combat implementation bugs. Applies to 4g and 5g networks. */ + public static final int NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST = 4; + /** LOCATION UPDATE REQUEST. Sample Reference: TS 24.008 4.4.3. Applies to 2g and 3g networks */ + public static final int NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST = 5; + /** AUTHENTICATION AND CIPHERING RESPONSE. Reference: 3GPP TS 24.008 4.7.7.1. + * Applies to 2g and 3g networks */ + public static final int NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE = 6; + /** REGISTRATION REQUEST. Reference: 3GPP TS 24.501 8.2.6. Applies to 5g networks */ + public static final int NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST = 7; + /** DEREGISTRATION REQUEST. Reference: 3GPP TS 24.501 8.2.12. Applies to 5g networks */ + public static final int NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST = 8; + /** CONNECTION MANAGEMENT REESTABLISHMENT REQUEST. Reference: 3GPP TS 24.008 9.2.4. + * Applies to 2g and 3g networks */ + public static final int NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST = 9; + /** CONNECTION MANAGEMENT SERVICE REQUEST. Reference: 3GPP TS 24.008 9.2.9. + * Applies to 2g and 3g networks */ + public static final int NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST = 10; + /** IMEI DETATCH INDICATION. Reference: 3GPP TS 24.008 9.2.14. + * Applies to 2g and 3g networks. Used for circuit-switched detach. */ + public static final int NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION = 11; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"NAS_PROTOCOL_MESSAGE_"}, value = {NAS_PROTOCOL_MESSAGE_UNKNOWN, + NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE, + NAS_PROTOCOL_MESSAGE_DETACH_REQUEST, NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST, + NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST, + NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE, + NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST, NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST, + NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST, + NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST, NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION}) + public @interface NasProtocolMessage { + } + + /* Cellular identifiers */ + /** Unknown */ + public static final int CELLULAR_IDENTIFIER_UNKNOWN = 0; + /** IMSI (International Mobile Subscriber Identity) */ + public static final int CELLULAR_IDENTIFIER_IMSI = 1; + /** IMEI (International Mobile Equipment Identity) */ + public static final int CELLULAR_IDENTIFIER_IMEI = 2; + /** 5G-specific SUCI (Subscription Concealed Identifier) */ + public static final int CELLULAR_IDENTIFIER_SUCI = 3; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"CELLULAR_IDENTIFIER_"}, value = {CELLULAR_IDENTIFIER_UNKNOWN, + CELLULAR_IDENTIFIER_IMSI, CELLULAR_IDENTIFIER_IMEI, CELLULAR_IDENTIFIER_SUCI}) + public @interface CellularIdentifier { + } + private @NasProtocolMessage int mNasProtocolMessage; private @CellularIdentifier int mCellularIdentifier; private String mPlmn; private boolean mIsEmergency; + /** + * Constructor for new CellularIdentifierDisclosure instances. + * + * @hide + */ + @TestApi public CellularIdentifierDisclosure(@NasProtocolMessage int nasProtocolMessage, - @CellularIdentifier int cellularIdentifier, String plmn, boolean isEmergency) { + @CellularIdentifier int cellularIdentifier, @NonNull String plmn, boolean isEmergency) { mNasProtocolMessage = nasProtocolMessage; mCellularIdentifier = cellularIdentifier; mPlmn = plmn; @@ -51,18 +128,30 @@ public final class CellularIdentifierDisclosure implements Parcelable { readFromParcel(in); } + /** + * @return the NAS protocol message associated with the disclosed identifier. + */ public @NasProtocolMessage int getNasProtocolMessage() { return mNasProtocolMessage; } + /** + * @return the identifier disclosed. + */ public @CellularIdentifier int getCellularIdentifier() { return mCellularIdentifier; } - public String getPlmn() { + /** + * @return the PLMN associated with the disclosure. + */ + @NonNull public String getPlmn() { return mPlmn; } + /** + * @return if the disclosure is associated with an emergency call. + */ public boolean isEmergency() { return mIsEmergency; } @@ -73,14 +162,14 @@ public final class CellularIdentifierDisclosure implements Parcelable { } @Override - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { out.writeInt(mNasProtocolMessage); out.writeInt(mCellularIdentifier); out.writeBoolean(mIsEmergency); out.writeString8(mPlmn); } - public static final Parcelable.Creator<CellularIdentifierDisclosure> CREATOR = + public static final @NonNull Parcelable.Creator<CellularIdentifierDisclosure> CREATOR = new Parcelable.Creator<CellularIdentifierDisclosure>() { public CellularIdentifierDisclosure createFromParcel(Parcel in) { return new CellularIdentifierDisclosure(in); @@ -120,42 +209,4 @@ public final class CellularIdentifierDisclosure implements Parcelable { mIsEmergency = in.readBoolean(); mPlmn = in.readString8(); } - - public static final int NAS_PROTOCOL_MESSAGE_UNKNOWN = 0; - public static final int NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST = 1; - public static final int NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE = 2; - public static final int NAS_PROTOCOL_MESSAGE_DETACH_REQUEST = 3; - public static final int NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST = 4; - public static final int NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST = 5; - public static final int NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE = 6; - public static final int NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST = 7; - public static final int NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST = 8; - public static final int NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST = 9; - public static final int NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST = 10; - public static final int NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION = 11; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"NAS_PROTOCOL_MESSAGE_"}, value = {NAS_PROTOCOL_MESSAGE_UNKNOWN, - NAS_PROTOCOL_MESSAGE_ATTACH_REQUEST, NAS_PROTOCOL_MESSAGE_IDENTITY_RESPONSE, - NAS_PROTOCOL_MESSAGE_DETACH_REQUEST, NAS_PROTOCOL_MESSAGE_TRACKING_AREA_UPDATE_REQUEST, - NAS_PROTOCOL_MESSAGE_LOCATION_UPDATE_REQUEST, - NAS_PROTOCOL_MESSAGE_AUTHENTICATION_AND_CIPHERING_RESPONSE, - NAS_PROTOCOL_MESSAGE_REGISTRATION_REQUEST, NAS_PROTOCOL_MESSAGE_DEREGISTRATION_REQUEST, - NAS_PROTOCOL_MESSAGE_CM_REESTABLISHMENT_REQUEST, - NAS_PROTOCOL_MESSAGE_CM_SERVICE_REQUEST, NAS_PROTOCOL_MESSAGE_IMSI_DETACH_INDICATION}) - public @interface NasProtocolMessage { - } - - public static final int CELLULAR_IDENTIFIER_UNKNOWN = 0; - public static final int CELLULAR_IDENTIFIER_IMSI = 1; - public static final int CELLULAR_IDENTIFIER_IMEI = 2; - public static final int CELLULAR_IDENTIFIER_SUCI = 3; - - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"CELLULAR_IDENTIFIER_"}, value = {CELLULAR_IDENTIFIER_UNKNOWN, - CELLULAR_IDENTIFIER_IMSI, CELLULAR_IDENTIFIER_IMEI, CELLULAR_IDENTIFIER_SUCI}) - public @interface CellularIdentifier { - } } diff --git a/telephony/java/android/telephony/SecurityAlgorithmUpdate.aidl b/telephony/java/android/telephony/SecurityAlgorithmUpdate.aidl new file mode 100644 index 000000000000..bee30bd43df9 --- /dev/null +++ b/telephony/java/android/telephony/SecurityAlgorithmUpdate.aidl @@ -0,0 +1,20 @@ +/* + * 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. + */ + +/** @hide */ +package android.telephony; + +parcelable SecurityAlgorithmUpdate; diff --git a/telephony/java/android/telephony/SecurityAlgorithmUpdate.java b/telephony/java/android/telephony/SecurityAlgorithmUpdate.java index 57209eb68de8..d635b555276b 100644 --- a/telephony/java/android/telephony/SecurityAlgorithmUpdate.java +++ b/telephony/java/android/telephony/SecurityAlgorithmUpdate.java @@ -16,11 +16,16 @@ package android.telephony; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.telephony.flags.Flags; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; @@ -31,112 +36,42 @@ import java.util.Objects; * * @hide */ +@SystemApi +@FlaggedApi(Flags.FLAG_SECURITY_ALGORITHMS_UPDATE_INDICATIONS) public final class SecurityAlgorithmUpdate implements Parcelable { private static final String TAG = "SecurityAlgorithmUpdate"; - private @ConnectionEvent int mConnectionEvent; - private @SecurityAlgorithm int mEncryption; - private @SecurityAlgorithm int mIntegrity; - private boolean mIsUnprotectedEmergency; - - public SecurityAlgorithmUpdate(@ConnectionEvent int connectionEvent, - @SecurityAlgorithm int encryption, @SecurityAlgorithm int integrity, - boolean isUnprotectedEmergency) { - mConnectionEvent = connectionEvent; - mEncryption = encryption; - mIntegrity = integrity; - mIsUnprotectedEmergency = isUnprotectedEmergency; - } - - private SecurityAlgorithmUpdate(Parcel in) { - readFromParcel(in); - } - - public @ConnectionEvent int getConnectionEvent() { - return mConnectionEvent; - } - - public @SecurityAlgorithm int getEncryption() { - return mEncryption; - } - - public @SecurityAlgorithm int getIntegrity() { - return mIntegrity; - } - - public boolean isUnprotectedEmergency() { - return mIsUnprotectedEmergency; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(mConnectionEvent); - out.writeInt(mEncryption); - out.writeInt(mIntegrity); - out.writeBoolean(mIsUnprotectedEmergency); - } - - private void readFromParcel(@NonNull Parcel in) { - mConnectionEvent = in.readInt(); - mEncryption = in.readInt(); - mIntegrity = in.readInt(); - mIsUnprotectedEmergency = in.readBoolean(); - } - - public static final Parcelable.Creator<SecurityAlgorithmUpdate> CREATOR = - new Parcelable.Creator<SecurityAlgorithmUpdate>() { - public SecurityAlgorithmUpdate createFromParcel(Parcel in) { - return new SecurityAlgorithmUpdate(in); - } - - public SecurityAlgorithmUpdate[] newArray(int size) { - return new SecurityAlgorithmUpdate[size]; - } - }; - - @Override - public String toString() { - return TAG + ":{ mConnectionEvent = " + mConnectionEvent + " mEncryption = " + mEncryption - + " mIntegrity = " + mIntegrity + " mIsUnprotectedEmergency = " - + mIsUnprotectedEmergency; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof SecurityAlgorithmUpdate)) return false; - SecurityAlgorithmUpdate that = (SecurityAlgorithmUpdate) o; - return mConnectionEvent == that.mConnectionEvent - && mEncryption == that.mEncryption - && mIntegrity == that.mIntegrity - && mIsUnprotectedEmergency == that.mIsUnprotectedEmergency; - } - - @Override - public int hashCode() { - return Objects.hash(mConnectionEvent, mEncryption, mIntegrity, mIsUnprotectedEmergency); - } - + /** 2G GSM circuit switched */ public static final int CONNECTION_EVENT_CS_SIGNALLING_GSM = 0; + /** 2G GPRS packet services */ public static final int CONNECTION_EVENT_PS_SIGNALLING_GPRS = 1; + /** 3G circuit switched*/ public static final int CONNECTION_EVENT_CS_SIGNALLING_3G = 2; + /** 3G packet switched*/ public static final int CONNECTION_EVENT_PS_SIGNALLING_3G = 3; + /** 4G Non-access stratum */ public static final int CONNECTION_EVENT_NAS_SIGNALLING_LTE = 4; + /** 4G Access-stratum */ public static final int CONNECTION_EVENT_AS_SIGNALLING_LTE = 5; + /** VOLTE SIP */ public static final int CONNECTION_EVENT_VOLTE_SIP = 6; + /** VOLTE SIP SOS (emergency) */ public static final int CONNECTION_EVENT_VOLTE_SIP_SOS = 7; + /** VOLTE RTP */ public static final int CONNECTION_EVENT_VOLTE_RTP = 8; + /** VOLTE RTP SOS (emergency) */ public static final int CONNECTION_EVENT_VOLTE_RTP_SOS = 9; + /** 5G Non-access stratum */ public static final int CONNECTION_EVENT_NAS_SIGNALLING_5G = 10; + /** 5G Access stratum */ public static final int CONNECTION_EVENT_AS_SIGNALLING_5G = 11; + /** VoNR SIP */ public static final int CONNECTION_EVENT_VONR_SIP = 12; + /** VoNR SIP SOS (emergency) */ public static final int CONNECTION_EVENT_VONR_SIP_SOS = 13; + /** VoNR RTP */ public static final int CONNECTION_EVENT_VONR_RTP = 14; + /** VoNR RTP SOS (emergency) */ public static final int CONNECTION_EVENT_VONR_RTP_SOS = 15; /** @hide */ @@ -153,48 +88,101 @@ public final class SecurityAlgorithmUpdate implements Parcelable { public @interface ConnectionEvent { } + /* GSM CS services, see 3GPP TS 43.020 for details */ + /** A5/0 - the null cipher */ public static final int SECURITY_ALGORITHM_A50 = 0; + /** A5/1 cipher */ public static final int SECURITY_ALGORITHM_A51 = 1; + /** A5/2 cipher */ public static final int SECURITY_ALGORITHM_A52 = 2; + /** A5/3 cipher */ public static final int SECURITY_ALGORITHM_A53 = 3; + /** A5/4 cipher */ public static final int SECURITY_ALGORITHM_A54 = 4; + /* GPRS PS services (3GPP TS 43.020) */ + /** GEA0 - null cipher */ public static final int SECURITY_ALGORITHM_GEA0 = 14; + /** GEA1 cipher */ public static final int SECURITY_ALGORITHM_GEA1 = 15; + /** GEA2 cipher */ public static final int SECURITY_ALGORITHM_GEA2 = 16; + /** GEA3 cipher */ public static final int SECURITY_ALGORITHM_GEA3 = 17; + /** GEA4 cipher */ public static final int SECURITY_ALGORITHM_GEA4 = 18; + /** GEA5 cipher */ public static final int SECURITY_ALGORITHM_GEA5 = 19; + /* 3G PS/CS services (3GPP TS 33.102) */ + /** UEA0 - null cipher */ public static final int SECURITY_ALGORITHM_UEA0 = 29; + /** UEA1 cipher */ public static final int SECURITY_ALGORITHM_UEA1 = 30; + /** UEA2 cipher */ public static final int SECURITY_ALGORITHM_UEA2 = 31; + /* 4G PS services & 5G NSA (3GPP TS 33.401) */ + /** EEA0 - null cipher */ public static final int SECURITY_ALGORITHM_EEA0 = 41; + /** EEA1 */ public static final int SECURITY_ALGORITHM_EEA1 = 42; + /** EEA2 */ public static final int SECURITY_ALGORITHM_EEA2 = 43; + /** EEA3 */ public static final int SECURITY_ALGORITHM_EEA3 = 44; + /* 5G PS services (3GPP TS 33.401 for 5G NSA and 3GPP TS 33.501 for 5G SA) */ + /** NEA0 - the null cipher */ public static final int SECURITY_ALGORITHM_NEA0 = 55; + /** NEA1 */ public static final int SECURITY_ALGORITHM_NEA1 = 56; + /** NEA2 */ public static final int SECURITY_ALGORITHM_NEA2 = 57; + /** NEA3 */ public static final int SECURITY_ALGORITHM_NEA3 = 58; + /* IMS and SIP layer security (See 3GPP TS 33.203) */ + /** No IPsec config */ public static final int SECURITY_ALGORITHM_SIP_NO_IPSEC_CONFIG = 66; + /** No IMS security, recommended to use SIP_NO_IPSEC_CONFIG and SIP_NULL instead */ public static final int SECURITY_ALGORITHM_IMS_NULL = 67; + /* IPSEC is present */ + /** SIP security is not enabled */ public static final int SECURITY_ALGORITHM_SIP_NULL = 68; + /** AES GCM mode */ public static final int SECURITY_ALGORITHM_AES_GCM = 69; + /** AES GMAC mode */ public static final int SECURITY_ALGORITHM_AES_GMAC = 70; + /** AES CBC mode */ public static final int SECURITY_ALGORITHM_AES_CBC = 71; + /** DES EDE3 CBC mode */ public static final int SECURITY_ALGORITHM_DES_EDE3_CBC = 72; + /** AES EDE3 CBC mode */ public static final int SECURITY_ALGORITHM_AES_EDE3_CBC = 73; + /** HMAC SHA1 96 */ public static final int SECURITY_ALGORITHM_HMAC_SHA1_96 = 74; + /** HMAC MD5 96 */ public static final int SECURITY_ALGORITHM_HMAC_MD5_96 = 75; + /* RTP and SRTP (see 3GPP TS 33.328) */ + /** RTP only, SRTP is not being used */ public static final int SECURITY_ALGORITHM_RTP = 85; + /* When SRTP is available and used */ + /** SRTP with null ciphering */ public static final int SECURITY_ALGORITHM_SRTP_NULL = 86; + /** SRTP with AES counter mode */ public static final int SECURITY_ALGORITHM_SRTP_AES_COUNTER = 87; + /** SRTP with AES F8 mode */ public static final int SECURITY_ALGORITHM_SRTP_AES_F8 = 88; + /** SRTP with HMAC SHA1 */ public static final int SECURITY_ALGORITHM_SRTP_HMAC_SHA1 = 89; + /* Ciphers for ePDG (3GPP TS 33.402) */ + /** ePDG encryption - AES GCM mode */ public static final int SECURITY_ALGORITHM_ENCR_AES_GCM_16 = 99; + /** ePDG encryption - AES GCM CBC mode */ public static final int SECURITY_ALGORITHM_ENCR_AES_CBC = 100; + /** ePDG authentication - HMAC SHA1 256 128 */ public static final int SECURITY_ALGORITHM_AUTH_HMAC_SHA2_256_128 = 101; + /** Unknown */ public static final int SECURITY_ALGORITHM_UNKNOWN = 113; + /** Other */ public static final int SECURITY_ALGORITHM_OTHER = 114; + /** Proprietary algorithms */ public static final int SECURITY_ALGORITHM_ORYX = 124; /** @hide */ @@ -220,4 +208,109 @@ public final class SecurityAlgorithmUpdate implements Parcelable { public @interface SecurityAlgorithm { } + private @ConnectionEvent int mConnectionEvent; + private @SecurityAlgorithm int mEncryption; + private @SecurityAlgorithm int mIntegrity; + private boolean mIsUnprotectedEmergency; + + /** + * Constructor for new SecurityAlgorithmUpdate instances. + * + * @hide + */ + @TestApi + public SecurityAlgorithmUpdate(@ConnectionEvent int connectionEvent, + @SecurityAlgorithm int encryption, @SecurityAlgorithm int integrity, + boolean isUnprotectedEmergency) { + mConnectionEvent = connectionEvent; + mEncryption = encryption; + mIntegrity = integrity; + mIsUnprotectedEmergency = isUnprotectedEmergency; + } + + private SecurityAlgorithmUpdate(Parcel in) { + readFromParcel(in); + } + + /** + * @return the connection event. + */ + public @ConnectionEvent int getConnectionEvent() { + return mConnectionEvent; + } + + /** + * @return the encryption algorithm. + */ + public @SecurityAlgorithm int getEncryption() { + return mEncryption; + } + + /** + * @return the integrity algorithm. + */ + public @SecurityAlgorithm int getIntegrity() { + return mIntegrity; + } + + /** + * @return if the security algorithm update is associated with an unprotected emergency call. + */ + public boolean isUnprotectedEmergency() { + return mIsUnprotectedEmergency; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mConnectionEvent); + out.writeInt(mEncryption); + out.writeInt(mIntegrity); + out.writeBoolean(mIsUnprotectedEmergency); + } + + private void readFromParcel(@NonNull Parcel in) { + mConnectionEvent = in.readInt(); + mEncryption = in.readInt(); + mIntegrity = in.readInt(); + mIsUnprotectedEmergency = in.readBoolean(); + } + + public static final @NonNull Parcelable.Creator<SecurityAlgorithmUpdate> CREATOR = + new Parcelable.Creator<SecurityAlgorithmUpdate>() { + public SecurityAlgorithmUpdate createFromParcel(Parcel in) { + return new SecurityAlgorithmUpdate(in); + } + + public SecurityAlgorithmUpdate[] newArray(int size) { + return new SecurityAlgorithmUpdate[size]; + } + }; + + @Override + public String toString() { + return TAG + ":{ mConnectionEvent = " + mConnectionEvent + " mEncryption = " + mEncryption + + " mIntegrity = " + mIntegrity + " mIsUnprotectedEmergency = " + + mIsUnprotectedEmergency; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof SecurityAlgorithmUpdate)) return false; + SecurityAlgorithmUpdate that = (SecurityAlgorithmUpdate) o; + return mConnectionEvent == that.mConnectionEvent + && mEncryption == that.mEncryption + && mIntegrity == that.mIntegrity + && mIsUnprotectedEmergency == that.mIsUnprotectedEmergency; + } + + @Override + public int hashCode() { + return Objects.hash(mConnectionEvent, mEncryption, mIntegrity, mIsUnprotectedEmergency); + } } diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java index 887b79883710..23203ed65e9a 100644 --- a/telephony/java/android/telephony/satellite/SatelliteManager.java +++ b/telephony/java/android/telephony/satellite/SatelliteManager.java @@ -281,6 +281,14 @@ public final class SatelliteManager { "satellite_access_configuration"; /** + * Bundle key to get the response from + * {@link #requestSelectedNbIotSatelliteSubscriptionId(Executor, OutcomeReceiver)}. + * @hide + */ + public static final String KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID = + "selected_nb_iot_satellite_subscription_id"; + + /** * The request was successfully processed. * @hide */ @@ -531,6 +539,12 @@ public final class SatelliteManager { @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS) public static final int SATELLITE_RESULT_ENABLE_IN_PROGRESS = 29; + /** + * There is no valid satellite subscription selected. + * @hide + */ + public static final int SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION = 30; + /** @hide */ @IntDef(prefix = {"SATELLITE_RESULT_"}, value = { SATELLITE_RESULT_SUCCESS, @@ -562,7 +576,8 @@ public final class SatelliteManager { SATELLITE_RESULT_LOCATION_NOT_AVAILABLE, SATELLITE_RESULT_EMERGENCY_CALL_IN_PROGRESS, SATELLITE_RESULT_DISABLE_IN_PROGRESS, - SATELLITE_RESULT_ENABLE_IN_PROGRESS + SATELLITE_RESULT_ENABLE_IN_PROGRESS, + SATELLITE_RESULT_NO_VALID_SATELLITE_SUBSCRIPTION }) @Retention(RetentionPolicy.SOURCE) public @interface SatelliteResult {} @@ -2464,6 +2479,68 @@ public final class SatelliteManager { } /** + * Request to get the currently selected satellite subscription id as an {@link Integer}. + * + * @param executor The executor on which the callback will be called. + * @param callback The callback object to which the result will be delivered. + * If the request is successful, {@link OutcomeReceiver#onResult(Object)} + * will return the time after which the satellite will be visible. + * If the request is not successful, {@link OutcomeReceiver#onError(Throwable)} + * will return a {@link SatelliteException} with the {@link SatelliteResult}. + * + * @throws SecurityException if the caller doesn't have required permission. + * + * @hide + */ + @RequiresPermission(Manifest.permission.SATELLITE_COMMUNICATION) + public void requestSelectedNbIotSatelliteSubscriptionId( + @NonNull @CallbackExecutor Executor executor, + @NonNull OutcomeReceiver<Integer, SatelliteException> callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); + + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + ResultReceiver receiver = new ResultReceiver(null) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == SATELLITE_RESULT_SUCCESS) { + if (resultData + .containsKey(KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID)) { + int selectedSatelliteSubscriptionId = + resultData + .getInt(KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onResult(selectedSatelliteSubscriptionId))); + } else { + loge( + "KEY_SELECTED_NB_IOT_SATELLITE_SUBSCRIPTION_ID does not exist." + ); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException( + SATELLITE_RESULT_REQUEST_FAILED)))); + } + } else { + executor.execute(() -> Binder.withCleanCallingIdentity(() -> + callback.onError(new SatelliteException(resultCode)))); + } + } + }; + telephony.requestSelectedNbIotSatelliteSubscriptionId(receiver); + } else { + loge("requestSelectedNbIotSatelliteSubscriptionId() invalid telephony"); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE)))); + } + } catch (RemoteException ex) { + loge("requestSelectedNbIotSatelliteSubscriptionId() RemoteException: " + ex); + executor.execute(() -> Binder.withCleanCallingIdentity(() -> callback.onError( + new SatelliteException(SATELLITE_RESULT_ILLEGAL_STATE)))); + } + } + + /** * Inform whether the device is aligned with the satellite in both real and demo mode. * * In demo mode, framework will send datagram to modem only when device is aligned with diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index a58427318b55..d22e9fa20101 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -3018,6 +3018,17 @@ interface ITelephony { + "android.Manifest.permission.SATELLITE_COMMUNICATION)") void requestTimeForNextSatelliteVisibility(in ResultReceiver receiver); + + /** + * Request to get the currently selected satellite subscription id. + * + * @param receiver Result receiver to get the error code of the request and the currently + * selected satellite subscription id. + */ + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(" + + "android.Manifest.permission.SATELLITE_COMMUNICATION)") + void requestSelectedNbIotSatelliteSubscriptionId(in ResultReceiver receiver); + /** * Inform whether the device is aligned with the satellite in both real and demo mode. * diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt index 9f5e6d18dc03..2c998c4217ac 100644 --- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt +++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt @@ -16,6 +16,7 @@ package com.android.server.wm.flicker.helpers +import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.content.Context import android.graphics.Insets import android.graphics.Rect @@ -74,13 +75,28 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : .waitForAndVerify() } + /** Launch an app and ensure it's moved to Desktop if it has not. */ + fun enterDesktopMode( + wmHelper: WindowManagerStateHelper, + device: UiDevice, + motionEventHelper: MotionEventHelper = MotionEventHelper(getInstrumentation(), TOUCH), + ) { + innerHelper.launchViaIntent(wmHelper) + if (!isInDesktopWindowingMode(wmHelper)) { + enterDesktopModeWithDrag( + wmHelper = wmHelper, + device = device, + motionEventHelper = motionEventHelper + ) + } + } + /** Move an app to Desktop by dragging the app handle at the top. */ - fun enterDesktopWithDrag( + fun enterDesktopModeWithDrag( wmHelper: WindowManagerStateHelper, device: UiDevice, motionEventHelper: MotionEventHelper = MotionEventHelper(getInstrumentation(), TOUCH) ) { - innerHelper.launchViaIntent(wmHelper) dragToDesktop( wmHelper = wmHelper, device = device, @@ -150,6 +166,25 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : .waitForAndVerify() } + private fun getHeaderEmptyView(caption: UiObject2?): UiObject2 { + return caption + ?.children + ?.find { it.resourceName.endsWith(HEADER_EMPTY_VIEW) } + ?: error("Unable to find resource $HEADER_EMPTY_VIEW\n") + } + + /** Click on an existing window's header to bring it to the front. */ + fun bringToFront(wmHelper: WindowManagerStateHelper, device: UiDevice) { + val caption = getCaptionForTheApp(wmHelper, device) + val openHeaderView = getHeaderEmptyView(caption) + openHeaderView.click() + wmHelper + .StateSyncBuilder() + .withAppTransitionIdle() + .withTopVisibleApp(innerHelper) + .waitForAndVerify() + } + /** Open maximize menu and click snap resize button on the app header for the given app. */ fun snapResizeDesktopApp( wmHelper: WindowManagerStateHelper, @@ -415,6 +450,10 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : return metricInsets.getInsetsIgnoringVisibility(typeMask) } + // Requirement of DesktopWindowingMode is having a minimum of 1 app in WINDOWING_MODE_FREEFORM. + private fun isInDesktopWindowingMode(wmHelper: WindowManagerStateHelper) = + wmHelper.getWindow(innerHelper)?.windowingMode == WINDOWING_MODE_FREEFORM + private companion object { val TIMEOUT: Duration = Duration.ofSeconds(3) const val SNAP_RESIZE_DRAG_INSET: Int = 5 // inset to avoid dragging to display edge @@ -427,6 +466,7 @@ open class DesktopModeAppHelper(private val innerHelper: IStandardAppHelper) : const val SNAP_LEFT_BUTTON: String = "maximize_menu_snap_left_button" const val SNAP_RIGHT_BUTTON: String = "maximize_menu_snap_right_button" const val MINIMIZE_BUTTON_VIEW: String = "minimize_window" + const val HEADER_EMPTY_VIEW: String = "caption_handle" val caption: BySelector get() = By.res(SYSTEMUI_PACKAGE, CAPTION) } diff --git a/tests/Input/res/xml/bookmarks.xml b/tests/Input/res/xml/bookmarks.xml index ba3f1871cdec..a4c898d8159a 100644 --- a/tests/Input/res/xml/bookmarks.xml +++ b/tests/Input/res/xml/bookmarks.xml @@ -14,47 +14,55 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<bookmarks> +<bookmarks xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"> <!-- the key combinations for the following shortcuts must be in sync with the key combinations sent by the test in KeyGestureControllerTests.java --> <bookmark role="android.app.role.BROWSER" - shortcut="b" /> + androidprv:keycode="KEYCODE_B" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CONTACTS" - shortcut="c" /> + androidprv:keycode="KEYCODE_C" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_EMAIL" - shortcut="e" /> + androidprv:keycode="KEYCODE_E" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CALENDAR" - shortcut="k" /> + androidprv:keycode="KEYCODE_K" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_MAPS" - shortcut="m" /> + androidprv:keycode="KEYCODE_M" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_MUSIC" - shortcut="p" /> + androidprv:keycode="KEYCODE_P" + androidprv:modifierState="META" /> <bookmark role="android.app.role.SMS" - shortcut="s" /> + androidprv:keycode="KEYCODE_S" + androidprv:modifierState="META" /> <bookmark category="android.intent.category.APP_CALCULATOR" - shortcut="u" /> + androidprv:keycode="KEYCODE_U" + androidprv:modifierState="META" /> <bookmark role="android.app.role.BROWSER" - shortcut="b" - shift="true" /> + androidprv:keycode="KEYCODE_B" + androidprv:modifierState="META|SHIFT" /> <bookmark category="android.intent.category.APP_CONTACTS" - shortcut="c" + androidprv:keycode="KEYCODE_C" shift="true" /> <bookmark package="com.test" class="com.test.BookmarkTest" - shortcut="j" + androidprv:keycode="KEYCODE_J" shift="true" /> </bookmarks>
\ No newline at end of file diff --git a/tests/Input/res/xml/bookmarks_legacy.xml b/tests/Input/res/xml/bookmarks_legacy.xml new file mode 100644 index 000000000000..8bacf490ad9e --- /dev/null +++ b/tests/Input/res/xml/bookmarks_legacy.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright 2024 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<bookmarks> + <!-- The key combinations for the following shortcuts are legacy way defining bookmarks and we + should prefer new way of defining bookmarks as shown in {@link bookmarks.xml} --> + <bookmark + role="android.app.role.BROWSER" + shortcut="b" /> + <bookmark + category="android.intent.category.APP_CONTACTS" + shortcut="c" /> + <bookmark + category="android.intent.category.APP_EMAIL" + shortcut="e" /> + <bookmark + category="android.intent.category.APP_CALENDAR" + shortcut="k" /> + <bookmark + category="android.intent.category.APP_MAPS" + shortcut="m" /> + <bookmark + category="android.intent.category.APP_MUSIC" + shortcut="p" /> + <bookmark + role="android.app.role.SMS" + shortcut="s" /> + <bookmark + category="android.intent.category.APP_CALCULATOR" + shortcut="u" /> + + <bookmark + role="android.app.role.BROWSER" + shortcut="b" + shift="true" /> + + <bookmark + category="android.intent.category.APP_CONTACTS" + shortcut="c" + shift="true" /> + + <bookmark + package="com.test" + class="com.test.BookmarkTest" + shortcut="j" + shift="true" /> +</bookmarks>
\ No newline at end of file diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt index 09a686ca2c3f..34350ab98046 100644 --- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt +++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt @@ -115,13 +115,11 @@ class KeyGestureControllerTests { private lateinit var iInputManager: IInputManager @Mock - private lateinit var resources: Resources - - @Mock private lateinit var packageManager: PackageManager private var currentPid = 0 private lateinit var context: Context + private lateinit var resources: Resources private lateinit var keyGestureController: KeyGestureController private lateinit var inputManagerGlobalSession: InputManagerGlobal.TestSession private lateinit var testLooper: TestLooper @@ -130,6 +128,7 @@ class KeyGestureControllerTests { @Before fun setup() { context = Mockito.spy(ContextWrapper(ApplicationProvider.getApplicationContext())) + resources = Mockito.spy(context.resources) setupInputDevices() setupBehaviors() testLooper = TestLooper() @@ -146,10 +145,6 @@ class KeyGestureControllerTests { private fun setupBehaviors() { Mockito.`when`(SystemProperties.get("ro.debuggable")).thenReturn("1") Mockito.`when`(resources.getBoolean(R.bool.config_enableScreenshotChord)).thenReturn(true) - val testBookmarks: XmlResourceParser = context.resources.getXml( - com.android.test.input.R.xml.bookmarks - ) - Mockito.`when`(resources.getXml(R.xml.bookmarks)).thenReturn(testBookmarks) Mockito.`when`(context.resources).thenReturn(resources) Mockito.`when`(packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) .thenReturn(true) @@ -158,6 +153,11 @@ class KeyGestureControllerTests { Mockito.`when`(context.packageManager).thenReturn(packageManager) } + private fun setupBookmarks(bookmarkRes: Int) { + val testBookmarks: XmlResourceParser = context.resources.getXml(bookmarkRes) + Mockito.`when`(resources.getXml(R.xml.bookmarks)).thenReturn(testBookmarks) + } + private fun setupInputDevices() { val correctIm = context.getSystemService(InputManager::class.java)!! val virtualDevice = correctIm.getInputDevice(KeyCharacterMap.VIRTUAL_KEYBOARD)!! @@ -604,45 +604,6 @@ class KeyGestureControllerTests { AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALCULATOR) ), TestData( - "META + SHIFT + B -> Launch Default Browser", - intArrayOf( - KeyEvent.KEYCODE_META_LEFT, - KeyEvent.KEYCODE_SHIFT_LEFT, - KeyEvent.KEYCODE_B - ), - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_B), - KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON, - intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), - AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER) - ), - TestData( - "META + SHIFT + C -> Launch Default Contacts", - intArrayOf( - KeyEvent.KEYCODE_META_LEFT, - KeyEvent.KEYCODE_SHIFT_LEFT, - KeyEvent.KEYCODE_C - ), - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_C), - KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON, - intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), - AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS) - ), - TestData( - "META + SHIFT + J -> Launch Target Activity", - intArrayOf( - KeyEvent.KEYCODE_META_LEFT, - KeyEvent.KEYCODE_SHIFT_LEFT, - KeyEvent.KEYCODE_J - ), - KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, - intArrayOf(KeyEvent.KEYCODE_J), - KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON, - intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), - AppLaunchData.createLaunchDataForComponent("com.test", "com.test.BookmarkTest") - ), - TestData( "META + CTRL + DEL -> Trigger Bug Report", intArrayOf( KeyEvent.KEYCODE_META_LEFT, @@ -715,47 +676,47 @@ class KeyGestureControllerTests { intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( - "ALT + [ -> Resizes a task to fit the left half of the screen", + "META + [ -> Resizes a task to fit the left half of the screen", intArrayOf( - KeyEvent.KEYCODE_ALT_LEFT, + KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_LEFT_BRACKET ), KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_LEFT_FREEFORM_WINDOW, intArrayOf(KeyEvent.KEYCODE_LEFT_BRACKET), - KeyEvent.META_ALT_ON, + KeyEvent.META_META_ON, intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( - "ALT + ] -> Resizes a task to fit the right half of the screen", + "META + ] -> Resizes a task to fit the right half of the screen", intArrayOf( - KeyEvent.KEYCODE_ALT_LEFT, + KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_RIGHT_BRACKET ), KeyGestureEvent.KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW, intArrayOf(KeyEvent.KEYCODE_RIGHT_BRACKET), - KeyEvent.META_ALT_ON, + KeyEvent.META_META_ON, intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( - "ALT + '=' -> Maximizes a task to fit the screen", + "META + '=' -> Toggles maximization of a task to maximized and restore its bounds", intArrayOf( - KeyEvent.KEYCODE_ALT_LEFT, + KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_EQUALS ), - KeyGestureEvent.KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW, + KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_MAXIMIZE_FREEFORM_WINDOW, intArrayOf(KeyEvent.KEYCODE_EQUALS), - KeyEvent.META_ALT_ON, + KeyEvent.META_META_ON, intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( - "ALT + '-' -> Restores a task size to its previous bounds", + "META + '-' -> Minimizes a freeform task", intArrayOf( - KeyEvent.KEYCODE_ALT_LEFT, + KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_MINUS ), - KeyGestureEvent.KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE, + KeyGestureEvent.KEY_GESTURE_TYPE_MINIMIZE_FREEFORM_WINDOW, intArrayOf(KeyEvent.KEYCODE_MINUS), - KeyEvent.META_ALT_ON, + KeyEvent.META_META_ON, intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE) ), TestData( @@ -866,6 +827,139 @@ class KeyGestureControllerTests { } @Keep + private fun bookmarkArguments(): Array<TestData> { + return arrayOf( + TestData( + "META + B -> Launch Default Browser", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_B), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_B), + KeyEvent.META_META_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER) + ), + TestData( + "META + C -> Launch Default Contacts", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_C), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_C), + KeyEvent.META_META_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS) + ), + TestData( + "META + E -> Launch Default Email", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_E), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_E), + KeyEvent.META_META_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_EMAIL) + ), + TestData( + "META + K -> Launch Default Calendar", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_K), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_K), + KeyEvent.META_META_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALENDAR) + ), + TestData( + "META + M -> Launch Default Maps", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_M), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_M), + KeyEvent.META_META_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_MAPS) + ), + TestData( + "META + P -> Launch Default Music", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_P), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_P), + KeyEvent.META_META_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_MUSIC) + ), + TestData( + "META + S -> Launch Default SMS", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_S), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_S), + KeyEvent.META_META_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_SMS) + ), + TestData( + "META + U -> Launch Default Calculator", + intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_U), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_U), + KeyEvent.META_META_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CALCULATOR) + ), + TestData( + "META + SHIFT + B -> Launch Default Browser", + intArrayOf( + KeyEvent.KEYCODE_META_LEFT, + KeyEvent.KEYCODE_SHIFT_LEFT, + KeyEvent.KEYCODE_B + ), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_B), + KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForRole(RoleManager.ROLE_BROWSER) + ), + TestData( + "META + SHIFT + C -> Launch Default Contacts", + intArrayOf( + KeyEvent.KEYCODE_META_LEFT, + KeyEvent.KEYCODE_SHIFT_LEFT, + KeyEvent.KEYCODE_C + ), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_C), + KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForCategory(Intent.CATEGORY_APP_CONTACTS) + ), + TestData( + "META + SHIFT + J -> Launch Target Activity", + intArrayOf( + KeyEvent.KEYCODE_META_LEFT, + KeyEvent.KEYCODE_SHIFT_LEFT, + KeyEvent.KEYCODE_J + ), + KeyGestureEvent.KEY_GESTURE_TYPE_LAUNCH_APPLICATION, + intArrayOf(KeyEvent.KEYCODE_J), + KeyEvent.META_META_ON or KeyEvent.META_SHIFT_ON, + intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE), + AppLaunchData.createLaunchDataForComponent("com.test", "com.test.BookmarkTest") + ) + ) + } + + @Test + @Parameters(method = "bookmarkArguments") + fun testBookmarks(test: TestData) { + setupBookmarks(com.android.test.input.R.xml.bookmarks) + setupKeyGestureController() + testKeyGestureInternal(test) + } + + @Test + @Parameters(method = "bookmarkArguments") + fun testBookmarksLegacy(test: TestData) { + setupBookmarks(com.android.test.input.R.xml.bookmarks_legacy) + setupKeyGestureController() + testKeyGestureInternal(test) + } + + @Keep private fun systemKeysTestArguments(): Array<TestData> { return arrayOf( TestData( diff --git a/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java b/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java index 2692e12c57ed..44641f7a1e12 100644 --- a/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java +++ b/tests/Tracing/src/com/android/internal/protolog/ProcessedPerfettoProtoLogImplTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -57,6 +58,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mockito; +import org.mockito.stubbing.Answer; import perfetto.protos.Protolog; import perfetto.protos.ProtologCommon; @@ -858,6 +860,39 @@ public class ProcessedPerfettoProtoLogImplTest { .isEqualTo("This message should also be logged 567"); } + @Test + public void enablesLogGroupAfterLoadingConfig() { + sProtoLog.stopLoggingToLogcat( + new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {}); + Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse(); + + doAnswer((Answer<Void>) invocation -> { + // logToLogcat is still false before we laod the viewer config + Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse(); + return null; + }).when(sReader).unloadViewerConfig(any(), any()); + + sProtoLog.startLoggingToLogcat( + new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {}); + Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isTrue(); + } + + @Test + public void disablesLogGroupBeforeUnloadingConfig() { + sProtoLog.startLoggingToLogcat( + new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {}); + Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isTrue(); + + doAnswer((Answer<Void>) invocation -> { + // Already set logToLogcat to false by the time we unload the config + Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse(); + return null; + }).when(sReader).unloadViewerConfig(any(), any()); + sProtoLog.stopLoggingToLogcat( + new String[] { TestProtoLogGroup.TEST_GROUP.name() }, (msg) -> {}); + Truth.assertThat(TestProtoLogGroup.TEST_GROUP.isLogToLogcat()).isFalse(); + } + private enum TestProtoLogGroup implements IProtoLogGroup { TEST_GROUP(true, true, false, "TEST_TAG"); diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp index 1bef5f8b17f6..1d4adc4a57d8 100644 --- a/tools/aapt2/link/TableMerger.cpp +++ b/tools/aapt2/link/TableMerger.cpp @@ -207,14 +207,13 @@ static ResourceTable::CollisionResult MergeConfigValue( Value* dst_value = dst_config_value->value.get(); Value* src_value = src_config_value->value.get(); - CollisionResult collision_result; - if (overlay) { - collision_result = - ResolveMergeCollision(override_styles_instead_of_overlaying, dst_value, src_value, pool); - } else { - collision_result = - ResourceTable::ResolveFlagCollision(dst_value->GetFlagStatus(), src_value->GetFlagStatus()); - if (collision_result == CollisionResult::kConflict) { + CollisionResult collision_result = + ResourceTable::ResolveFlagCollision(dst_value->GetFlagStatus(), src_value->GetFlagStatus()); + if (collision_result == CollisionResult::kConflict) { + if (overlay) { + collision_result = + ResolveMergeCollision(override_styles_instead_of_overlaying, dst_value, src_value, pool); + } else { collision_result = ResourceTable::ResolveValueCollision(dst_value, src_value); } } diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java index f68ae2c7e249..74a907f8ae22 100644 --- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java +++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java @@ -309,7 +309,7 @@ public class SharedConnectivityManager { */ @TestApi @NonNull - @FlaggedApi("com.android.wifi.flags.shared_connectivity_broadcast_receiver_test_api") + @SuppressLint("UnflaggedApi") // Exempt: Test API for already shipped feature public BroadcastReceiver getBroadcastReceiver() { return mBroadcastReceiver; } |