diff options
91 files changed, 1389 insertions, 714 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 22af517900d2..93f311969c1e 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -18570,13 +18570,13 @@ package android.telephony.satellite { @FlaggedApi("com.android.internal.telephony.flags.satellite_state_change_listener") public final class SatelliteManager { method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void addAttachRestrictionForCarrier(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatellite(@NonNull java.util.List<android.telephony.satellite.SatelliteSubscriberInfo>, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>); + method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionSatellite(@NonNull java.util.List<android.telephony.satellite.SatelliteSubscriberInfo>, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telephony.satellite.SatelliteManager.SatelliteException>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void deprovisionService(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.Set<java.lang.Integer> getAttachRestrictionReasonsForCarrier(int); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int[] getSatelliteDisallowedReasons(); method @FlaggedApi("com.android.internal.telephony.flags.carrier_enabled_satellite_flag") @NonNull @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public java.util.List<java.lang.String> getSatellitePlmnsForCarrier(int); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void pollPendingDatagrams(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatellite(@NonNull java.util.List<android.telephony.satellite.SatelliteSubscriberInfo>, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Boolean,android.telephony.satellite.SatelliteManager.SatelliteException>); + method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionSatellite(@NonNull java.util.List<android.telephony.satellite.SatelliteSubscriberInfo>, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telephony.satellite.SatelliteManager.SatelliteException>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public void provisionService(@NonNull String, @NonNull byte[], @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); method @FlaggedApi("com.android.internal.telephony.flags.oem_enabled_satellite_flag") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForCapabilitiesChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteCapabilitiesCallback); method @FlaggedApi("com.android.internal.telephony.flags.satellite_system_apis") @RequiresPermission(android.Manifest.permission.SATELLITE_COMMUNICATION) public int registerForCommunicationAccessStateChanged(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.satellite.SatelliteCommunicationAccessStateCallback); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 614e2aaf42e8..5176aee9051f 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -5856,7 +5856,9 @@ public class Notification implements Parcelable return null; } final int size = mContext.getResources().getDimensionPixelSize( - R.dimen.notification_badge_size); + Flags.notificationsRedesignTemplates() + ? R.dimen.notification_2025_badge_size + : R.dimen.notification_badge_size); Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); badge.setBounds(0, 0, size, size); diff --git a/core/java/android/app/time/TimeZoneCapabilities.java b/core/java/android/app/time/TimeZoneCapabilities.java index 4dee15988795..929f66079a3d 100644 --- a/core/java/android/app/time/TimeZoneCapabilities.java +++ b/core/java/android/app/time/TimeZoneCapabilities.java @@ -55,7 +55,8 @@ public final class TimeZoneCapabilities implements Parcelable { * The user the capabilities are for. This is used for object equality and debugging but there * is no accessor. */ - @NonNull private final UserHandle mUserHandle; + @NonNull + private final UserHandle mUserHandle; private final @CapabilityState int mConfigureAutoDetectionEnabledCapability; /** @@ -69,6 +70,7 @@ public final class TimeZoneCapabilities implements Parcelable { private final @CapabilityState int mConfigureGeoDetectionEnabledCapability; private final @CapabilityState int mSetManualTimeZoneCapability; + private final @CapabilityState int mConfigureNotificationsEnabledCapability; private TimeZoneCapabilities(@NonNull Builder builder) { this.mUserHandle = Objects.requireNonNull(builder.mUserHandle); @@ -78,6 +80,8 @@ public final class TimeZoneCapabilities implements Parcelable { this.mConfigureGeoDetectionEnabledCapability = builder.mConfigureGeoDetectionEnabledCapability; this.mSetManualTimeZoneCapability = builder.mSetManualTimeZoneCapability; + this.mConfigureNotificationsEnabledCapability = + builder.mConfigureNotificationsEnabledCapability; } @NonNull @@ -88,6 +92,7 @@ public final class TimeZoneCapabilities implements Parcelable { .setUseLocationEnabled(in.readBoolean()) .setConfigureGeoDetectionEnabledCapability(in.readInt()) .setSetManualTimeZoneCapability(in.readInt()) + .setConfigureNotificationsEnabledCapability(in.readInt()) .build(); } @@ -98,6 +103,7 @@ public final class TimeZoneCapabilities implements Parcelable { dest.writeBoolean(mUseLocationEnabled); dest.writeInt(mConfigureGeoDetectionEnabledCapability); dest.writeInt(mSetManualTimeZoneCapability); + dest.writeInt(mConfigureNotificationsEnabledCapability); } /** @@ -117,8 +123,8 @@ public final class TimeZoneCapabilities implements Parcelable { * * Not part of the SDK API because it is intended for use by SettingsUI, which can display * text about needing it to be on for location-based time zone detection. - * @hide * + * @hide */ public boolean isUseLocationEnabled() { return mUseLocationEnabled; @@ -148,6 +154,18 @@ public final class TimeZoneCapabilities implements Parcelable { } /** + * Returns the capability state associated with the user's ability to modify the time zone + * notification setting. The setting can be updated via {@link + * TimeManager#updateTimeZoneConfiguration(TimeZoneConfiguration)}. + * + * @hide + */ + @CapabilityState + public int getConfigureNotificationsEnabledCapability() { + return mConfigureNotificationsEnabledCapability; + } + + /** * Tries to create a new {@link TimeZoneConfiguration} from the {@code config} and the set of * {@code requestedChanges}, if {@code this} capabilities allow. The new configuration is * returned. If the capabilities do not permit one or more of the requested changes then {@code @@ -174,6 +192,12 @@ public final class TimeZoneCapabilities implements Parcelable { newConfigBuilder.setGeoDetectionEnabled(requestedChanges.isGeoDetectionEnabled()); } + if (requestedChanges.hasIsNotificationsEnabled()) { + if (this.getConfigureNotificationsEnabledCapability() < CAPABILITY_NOT_APPLICABLE) { + return null; + } + newConfigBuilder.setNotificationsEnabled(requestedChanges.areNotificationsEnabled()); + } return newConfigBuilder.build(); } @@ -197,13 +221,16 @@ public final class TimeZoneCapabilities implements Parcelable { && mUseLocationEnabled == that.mUseLocationEnabled && mConfigureGeoDetectionEnabledCapability == that.mConfigureGeoDetectionEnabledCapability - && mSetManualTimeZoneCapability == that.mSetManualTimeZoneCapability; + && mSetManualTimeZoneCapability == that.mSetManualTimeZoneCapability + && mConfigureNotificationsEnabledCapability + == that.mConfigureNotificationsEnabledCapability; } @Override public int hashCode() { return Objects.hash(mUserHandle, mConfigureAutoDetectionEnabledCapability, - mConfigureGeoDetectionEnabledCapability, mSetManualTimeZoneCapability); + mConfigureGeoDetectionEnabledCapability, mSetManualTimeZoneCapability, + mConfigureNotificationsEnabledCapability); } @Override @@ -216,6 +243,8 @@ public final class TimeZoneCapabilities implements Parcelable { + ", mConfigureGeoDetectionEnabledCapability=" + mConfigureGeoDetectionEnabledCapability + ", mSetManualTimeZoneCapability=" + mSetManualTimeZoneCapability + + ", mConfigureNotificationsEnabledCapability=" + + mConfigureNotificationsEnabledCapability + '}'; } @@ -226,11 +255,13 @@ public final class TimeZoneCapabilities implements Parcelable { */ public static class Builder { - @NonNull private UserHandle mUserHandle; + @NonNull + private UserHandle mUserHandle; private @CapabilityState int mConfigureAutoDetectionEnabledCapability; private Boolean mUseLocationEnabled; private @CapabilityState int mConfigureGeoDetectionEnabledCapability; private @CapabilityState int mSetManualTimeZoneCapability; + private @CapabilityState int mConfigureNotificationsEnabledCapability; public Builder(@NonNull UserHandle userHandle) { mUserHandle = Objects.requireNonNull(userHandle); @@ -240,12 +271,14 @@ public final class TimeZoneCapabilities implements Parcelable { Objects.requireNonNull(capabilitiesToCopy); mUserHandle = capabilitiesToCopy.mUserHandle; mConfigureAutoDetectionEnabledCapability = - capabilitiesToCopy.mConfigureAutoDetectionEnabledCapability; + capabilitiesToCopy.mConfigureAutoDetectionEnabledCapability; mUseLocationEnabled = capabilitiesToCopy.mUseLocationEnabled; mConfigureGeoDetectionEnabledCapability = - capabilitiesToCopy.mConfigureGeoDetectionEnabledCapability; + capabilitiesToCopy.mConfigureGeoDetectionEnabledCapability; mSetManualTimeZoneCapability = - capabilitiesToCopy.mSetManualTimeZoneCapability; + capabilitiesToCopy.mSetManualTimeZoneCapability; + mConfigureNotificationsEnabledCapability = + capabilitiesToCopy.mConfigureNotificationsEnabledCapability; } /** Sets the value for the "configure automatic time zone detection enabled" capability. */ @@ -274,6 +307,14 @@ public final class TimeZoneCapabilities implements Parcelable { return this; } + /** + * Sets the value for the "configure time notifications enabled" capability. + */ + public Builder setConfigureNotificationsEnabledCapability(@CapabilityState int value) { + this.mConfigureNotificationsEnabledCapability = value; + return this; + } + /** Returns the {@link TimeZoneCapabilities}. */ @NonNull public TimeZoneCapabilities build() { @@ -283,7 +324,9 @@ public final class TimeZoneCapabilities implements Parcelable { verifyCapabilitySet(mConfigureGeoDetectionEnabledCapability, "configureGeoDetectionEnabledCapability"); verifyCapabilitySet(mSetManualTimeZoneCapability, - "mSetManualTimeZoneCapability"); + "setManualTimeZoneCapability"); + verifyCapabilitySet(mConfigureNotificationsEnabledCapability, + "configureNotificationsEnabledCapability"); return new TimeZoneCapabilities(this); } diff --git a/core/java/android/app/time/TimeZoneConfiguration.java b/core/java/android/app/time/TimeZoneConfiguration.java index 7403c129f4dc..68c090f6dde3 100644 --- a/core/java/android/app/time/TimeZoneConfiguration.java +++ b/core/java/android/app/time/TimeZoneConfiguration.java @@ -62,7 +62,8 @@ public final class TimeZoneConfiguration implements Parcelable { * * @hide */ - @StringDef({ SETTING_AUTO_DETECTION_ENABLED, SETTING_GEO_DETECTION_ENABLED }) + @StringDef({SETTING_AUTO_DETECTION_ENABLED, SETTING_GEO_DETECTION_ENABLED, + SETTING_NOTIFICATIONS_ENABLED}) @Retention(RetentionPolicy.SOURCE) @interface Setting {} @@ -74,6 +75,10 @@ public final class TimeZoneConfiguration implements Parcelable { @Setting private static final String SETTING_GEO_DETECTION_ENABLED = "geoDetectionEnabled"; + /** See {@link TimeZoneConfiguration#areNotificationsEnabled()} for details. */ + @Setting + private static final String SETTING_NOTIFICATIONS_ENABLED = "notificationsEnabled"; + @NonNull private final Bundle mBundle; private TimeZoneConfiguration(Builder builder) { @@ -98,7 +103,8 @@ public final class TimeZoneConfiguration implements Parcelable { */ public boolean isComplete() { return hasIsAutoDetectionEnabled() - && hasIsGeoDetectionEnabled(); + && hasIsGeoDetectionEnabled() + && hasIsNotificationsEnabled(); } /** @@ -128,8 +134,7 @@ public final class TimeZoneConfiguration implements Parcelable { /** * Returns the value of the {@link #SETTING_GEO_DETECTION_ENABLED} setting. This * controls whether the device can use geolocation to determine time zone. This value may only - * be used by Android under some circumstances. For example, it is not used when - * {@link #isGeoDetectionEnabled()} is {@code false}. + * be used by Android under some circumstances. * * <p>See {@link TimeZoneCapabilities#getConfigureGeoDetectionEnabledCapability()} for how to * tell if the setting is meaningful for the current user at this time. @@ -150,6 +155,32 @@ public final class TimeZoneConfiguration implements Parcelable { return mBundle.containsKey(SETTING_GEO_DETECTION_ENABLED); } + /** + * Returns the value of the {@link #SETTING_NOTIFICATIONS_ENABLED} setting. This controls + * whether the device can send time and time zone related notifications. This value may only + * be used by Android under some circumstances. + * + * <p>See {@link TimeZoneCapabilities#getConfigureNotificationsEnabledCapability()} ()} for how + * to tell if the setting is meaningful for the current user at this time. + * + * @throws IllegalStateException if the setting is not present + * + * @hide + */ + public boolean areNotificationsEnabled() { + enforceSettingPresent(SETTING_NOTIFICATIONS_ENABLED); + return mBundle.getBoolean(SETTING_NOTIFICATIONS_ENABLED); + } + + /** + * Returns {@code true} if the {@link #areNotificationsEnabled()} setting is present. + * + * @hide + */ + public boolean hasIsNotificationsEnabled() { + return mBundle.containsKey(SETTING_NOTIFICATIONS_ENABLED); + } + @Override public int describeContents() { return 0; @@ -244,6 +275,17 @@ public final class TimeZoneConfiguration implements Parcelable { return this; } + /** + * Sets the state of the {@link #SETTING_NOTIFICATIONS_ENABLED} setting. * + * + * @hide + */ + @NonNull + public Builder setNotificationsEnabled(boolean enabled) { + this.mBundle.putBoolean(SETTING_NOTIFICATIONS_ENABLED, enabled); + return this; + } + /** Returns the {@link TimeZoneConfiguration}. */ @NonNull public TimeZoneConfiguration build() { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ec58eff92410..11dddfb24ad5 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -13328,6 +13328,16 @@ public final class Settings { public static final String AUTO_TIME_ZONE_EXPLICIT = "auto_time_zone_explicit"; /** + * Value to specify if the device should send notifications when {@link #AUTO_TIME_ZONE} is + * on and the device's time zone changes. + * + * <p>1=yes, 0=no. + * + * @hide + */ + public static final String TIME_ZONE_NOTIFICATIONS = "time_zone_notifications"; + + /** * URI for the car dock "in" event sound. * @hide */ diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java index 20e3f6b93bd0..2911b0a6643d 100644 --- a/core/java/android/window/WindowOnBackInvokedDispatcher.java +++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java @@ -464,7 +464,12 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { * Returns false if the legacy back behavior should be used. */ public boolean isOnBackInvokedCallbackEnabled() { - return isOnBackInvokedCallbackEnabled(mChecker.getContext()); + final Context hostContext = mChecker.getContext(); + if (hostContext == null) { + Log.w(TAG, "OnBackInvokedCallback is disabled, host context is removed!"); + return false; + } + return isOnBackInvokedCallbackEnabled(hostContext); } /** @@ -695,7 +700,12 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { */ public boolean checkApplicationCallbackRegistration(int priority, OnBackInvokedCallback callback) { - if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(getContext()) + final Context hostContext = getContext(); + if (hostContext == null) { + Log.w(TAG, "OnBackInvokedCallback is disabled, host context is removed!"); + return false; + } + if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(hostContext) && !(callback instanceof CompatOnBackInvokedCallback)) { Log.w(TAG, "OnBackInvokedCallback is not enabled for the application." @@ -720,7 +730,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { return true; } - private Context getContext() { + @Nullable private Context getContext() { return mContext.get(); } } diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java index 5635943cb76e..972c2ea403e0 100644 --- a/core/java/com/android/internal/notification/SystemNotificationChannels.java +++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java @@ -49,6 +49,7 @@ public class SystemNotificationChannels { public static final String NETWORK_ALERTS = "NETWORK_ALERTS"; public static final String NETWORK_AVAILABLE = "NETWORK_AVAILABLE"; public static final String VPN = "VPN"; + public static final String TIME = "TIME"; /** * @deprecated Legacy device admin channel with low importance which is no longer used, * Use the high importance {@link #DEVICE_ADMIN} channel instead. @@ -146,6 +147,12 @@ public class SystemNotificationChannels { NotificationManager.IMPORTANCE_LOW); channelsList.add(vpn); + final NotificationChannel time = new NotificationChannel( + TIME, + context.getString(R.string.notification_channel_system_time), + NotificationManager.IMPORTANCE_DEFAULT); + channelsList.add(time); + final NotificationChannel deviceAdmin = new NotificationChannel( DEVICE_ADMIN, getDeviceAdminNotificationChannelName(context), diff --git a/core/res/res/layout/notification_2025_conversation_header.xml b/core/res/res/layout/notification_2025_conversation_header.xml index db79e79c96df..1bde17358825 100644 --- a/core/res/res/layout/notification_2025_conversation_header.xml +++ b/core/res/res/layout/notification_2025_conversation_header.xml @@ -136,10 +136,10 @@ <ImageView android:id="@+id/phishing_alert" - android:layout_width="@dimen/notification_phishing_alert_size" - android:layout_height="@dimen/notification_phishing_alert_size" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:baseline="10dp" + android:layout_width="@dimen/notification_2025_badge_size" + android:layout_height="@dimen/notification_2025_badge_size" + android:layout_marginStart="@dimen/notification_2025_badge_margin" + android:baseline="@dimen/notification_2025_badge_baseline" android:scaleType="fitCenter" android:src="@drawable/ic_dialog_alert_material" android:visibility="gone" @@ -148,10 +148,10 @@ <ImageView android:id="@+id/profile_badge" - android:layout_width="@dimen/notification_badge_size" - android:layout_height="@dimen/notification_badge_size" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:baseline="10dp" + android:layout_width="@dimen/notification_2025_badge_size" + android:layout_height="@dimen/notification_2025_badge_size" + android:layout_marginStart="@dimen/notification_2025_badge_margin" + android:baseline="@dimen/notification_2025_badge_baseline" android:scaleType="fitCenter" android:visibility="gone" android:contentDescription="@string/notification_work_profile_content_description" @@ -159,10 +159,10 @@ <ImageView android:id="@+id/alerted_icon" - android:layout_width="@dimen/notification_alerted_size" - android:layout_height="@dimen/notification_alerted_size" - android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" - android:baseline="10dp" + android:layout_width="@dimen/notification_2025_badge_size" + android:layout_height="@dimen/notification_2025_badge_size" + android:layout_marginStart="@dimen/notification_2025_badge_margin" + android:baseline="@dimen/notification_2025_badge_baseline" android:contentDescription="@string/notification_alerted_content_description" android:scaleType="fitCenter" android:src="@drawable/ic_notifications_alerted" diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml index f108ce5bd1b9..d29b7af9e24e 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_base.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml @@ -87,7 +87,7 @@ > <!-- - NOTE: The notification_top_line_views layout contains the app_name_text. + NOTE: The notification_2025_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. --> @@ -104,7 +104,7 @@ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" /> - <include layout="@layout/notification_top_line_views" /> + <include layout="@layout/notification_2025_top_line_views" /> </NotificationTopLineView> diff --git a/core/res/res/layout/notification_2025_template_collapsed_media.xml b/core/res/res/layout/notification_2025_template_collapsed_media.xml index bd17a3a0a74e..5beab508aecf 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_media.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_media.xml @@ -89,7 +89,7 @@ > <!-- - NOTE: The notification_top_line_views layout contains the app_name_text. + NOTE: The notification_2025_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. --> @@ -106,7 +106,7 @@ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" /> - <include layout="@layout/notification_top_line_views" /> + <include layout="@layout/notification_2025_top_line_views" /> </NotificationTopLineView> diff --git a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml index edbebb17f825..d7c3263904d4 100644 --- a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml +++ b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml @@ -115,7 +115,7 @@ > <!-- - NOTE: The notification_top_line_views layout contains the app_name_text. + NOTE: The notification_2025_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. --> @@ -132,7 +132,7 @@ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" /> - <include layout="@layout/notification_top_line_views" /> + <include layout="@layout/notification_2025_top_line_views" /> </NotificationTopLineView> diff --git a/core/res/res/layout/notification_2025_template_header.xml b/core/res/res/layout/notification_2025_template_header.xml index 0c07053d428a..72b3798e0780 100644 --- a/core/res/res/layout/notification_2025_template_header.xml +++ b/core/res/res/layout/notification_2025_template_header.xml @@ -68,7 +68,7 @@ android:theme="@style/Theme.DeviceDefault.Notification" > - <include layout="@layout/notification_top_line_views" /> + <include layout="@layout/notification_2025_top_line_views" /> </NotificationTopLineView> diff --git a/core/res/res/layout/notification_2025_template_heads_up_base.xml b/core/res/res/layout/notification_2025_template_heads_up_base.xml index e4ff835a3524..084ec7daa683 100644 --- a/core/res/res/layout/notification_2025_template_heads_up_base.xml +++ b/core/res/res/layout/notification_2025_template_heads_up_base.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?><!-- - ~ Copyright (C) 2014 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. diff --git a/core/res/res/layout/notification_2025_top_line_views.xml b/core/res/res/layout/notification_2025_top_line_views.xml new file mode 100644 index 000000000000..74873463391e --- /dev/null +++ b/core/res/res/layout/notification_2025_top_line_views.xml @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2025 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<!-- + This layout file should be included inside a NotificationTopLineView, sometimes after a + <TextView android:id="@+id/title"/> +--> +<merge + xmlns:android="http://schemas.android.com/apk/res/android"> + + <TextView + android:id="@+id/app_name_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:singleLine="true" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:visibility="?attr/notificationHeaderAppNameVisibility" + /> + + <TextView + android:id="@+id/header_text_secondary_divider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:text="@string/notification_header_divider_symbol" + android:visibility="gone" + /> + + <TextView + android:id="@+id/header_text_secondary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:visibility="gone" + android:singleLine="true" + /> + + <TextView + android:id="@+id/header_text_divider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:text="@string/notification_header_divider_symbol" + android:visibility="gone" + /> + + <TextView + android:id="@+id/header_text" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:visibility="gone" + android:singleLine="true" + /> + + <TextView + android:id="@+id/time_divider" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:text="@string/notification_header_divider_symbol" + android:singleLine="true" + android:visibility="gone" + /> + + <DateTimeView + android:id="@+id/time" + android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:showRelative="true" + android:singleLine="true" + android:visibility="gone" + /> + + <ViewStub + android:id="@+id/chronometer" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:layout="@layout/notification_template_part_chronometer" + android:visibility="gone" + /> + + <ImageButton + android:id="@+id/feedback" + android:layout_width="@dimen/notification_feedback_size" + android:layout_height="@dimen/notification_feedback_size" + android:layout_marginStart="@dimen/notification_header_separating_margin" + android:baseline="13dp" + android:scaleType="fitCenter" + android:src="@drawable/ic_feedback_indicator" + android:background="?android:selectableItemBackgroundBorderless" + android:visibility="gone" + android:contentDescription="@string/notification_feedback_indicator" + /> + + <ImageView + android:id="@+id/phishing_alert" + android:layout_width="@dimen/notification_2025_badge_size" + android:layout_height="@dimen/notification_2025_badge_size" + android:layout_marginStart="@dimen/notification_2025_badge_margin" + android:baseline="@dimen/notification_2025_badge_baseline" + android:scaleType="fitCenter" + android:src="@drawable/ic_dialog_alert_material" + android:visibility="gone" + android:contentDescription="@string/notification_phishing_alert_content_description" + /> + + <ImageView + android:id="@+id/profile_badge" + android:layout_width="@dimen/notification_2025_badge_size" + android:layout_height="@dimen/notification_2025_badge_size" + android:layout_marginStart="@dimen/notification_2025_badge_margin" + android:baseline="@dimen/notification_2025_badge_baseline" + android:scaleType="fitCenter" + android:visibility="gone" + android:contentDescription="@string/notification_work_profile_content_description" + /> + + <ImageView + android:id="@+id/alerted_icon" + android:layout_width="@dimen/notification_2025_badge_size" + android:layout_height="@dimen/notification_2025_badge_size" + android:layout_marginStart="@dimen/notification_2025_badge_margin" + android:baseline="@dimen/notification_2025_badge_baseline" + android:contentDescription="@string/notification_alerted_content_description" + android:scaleType="fitCenter" + android:src="@drawable/ic_notifications_alerted" + android:visibility="gone" + /> +</merge> + diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml index e6295ea06177..4ff3f8825cc4 100644 --- a/core/res/res/values-watch/config.xml +++ b/core/res/res/values-watch/config.xml @@ -101,6 +101,13 @@ P.S this is a change only intended for wear devices. --> <bool name="config_enableViewGroupScalingFading">true</bool> - <!-- Allow the gesture to double tap the power button to trigger a target action. --> - <bool name="config_doubleTapPowerGestureEnabled">false</bool> + <!-- Controls the double tap power button gesture to trigger a target action. + 0: Gesture is disabled + 1: Launch camera mode, allowing the user to disable/enable the double tap power gesture + from launching the camera application. + 2: Multi target mode, allowing the user to select one of the targets defined in + config_doubleTapPowerGestureMultiTargetDefaultAction and to disable/enable the double + tap power gesture from triggering the selected target action. + --> + <integer name="config_doubleTapPowerGestureMode">0</integer> </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index c50c5e9d3341..ce9a0c636d62 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2083,6 +2083,18 @@ See com.android.server.timezonedetector.TimeZoneDetectorStrategy for more information. --> <bool name="config_supportTelephonyTimeZoneFallback" translatable="false">true</bool> + <!-- Whether the time notifications feature is enabled. Settings this to false means the feature + cannot be used. Setting this to true means the feature can be enabled on the device. --> + <bool name="config_enableTimeZoneNotificationsSupported" translatable="false">true</bool> + + <!-- Whether the time zone notifications tracking feature is enabled. Settings this to false + means the feature cannot be used. --> + <bool name="config_enableTimeZoneNotificationsTrackingSupported" translatable="false">true</bool> + + <!-- Whether the time zone manual change tracking feature is enabled. Settings this to false + means the feature cannot be used. --> + <bool name="config_enableTimeZoneManualChangeTrackingSupported" translatable="false">true</bool> + <!-- Whether to enable network location overlay which allows network location provider to be replaced by an app at run-time. When disabled, only the config_networkLocationProviderPackageName package will be searched for network location diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 2adb79118ed9..4f7351c7cc4d 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -608,12 +608,23 @@ <!-- Size of the feedback indicator for notifications --> <dimen name="notification_feedback_size">20dp</dimen> + <!-- Size of the (work) profile badge for notifications --> + <dimen name="notification_badge_size">12dp</dimen> + + <!-- Size of the (work) profile badge for notifications (2025 redesign version). + Scales with font size. Chosen to look good alongside notification_subtext_size text. --> + <dimen name="notification_2025_badge_size">14sp</dimen> + + <!-- Baseline for aligning icons in the top line (like the work profile icon or alerting icon) + to the text properly. This is equal to notification_2025_badge_size - 2sp. --> + <dimen name="notification_2025_badge_baseline">12sp</dimen> + + <!-- Spacing for the top line icons (e.g. the work profile badge). --> + <dimen name="notification_2025_badge_margin">4dp</dimen> + <!-- Size of the phishing alert for notifications --> <dimen name="notification_phishing_alert_size">@dimen/notification_badge_size</dimen> - <!-- Size of the profile badge for notifications --> - <dimen name="notification_badge_size">12dp</dimen> - <!-- Size of the alerted icon for notifications --> <dimen name="notification_alerted_size">@dimen/notification_badge_size</dimen> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index ad9e7252c6a8..debc5e9a0dce 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -853,6 +853,9 @@ <!-- Text shown when viewing channel settings for notifications related to vpn status --> <string name="notification_channel_vpn">VPN status</string> + <!-- Text shown when viewing channel settings for notifications related to system time --> + <string name="notification_channel_system_time">Time and time zones</string> + <!-- Notification channel name. This channel sends high-priority alerts from the user's IT admin for key updates about the user's work device or work profile. --> <string name="notification_channel_device_admin">Alerts from your IT admin</string> @@ -3879,6 +3882,12 @@ <string name="carrier_app_notification_title">New SIM inserted</string> <string name="carrier_app_notification_text">Tap to set it up</string> + <!-- Time zone notification strings --> + <!-- Title for time zone change notifications --> + <string name="time_zone_change_notification_title">Your time zone changed</string> + <!-- Body for time zone change notifications --> + <string name="time_zone_change_notification_body">You\'re now in <xliff:g id="time_zone_display_name">%1$s</xliff:g> (<xliff:g id="time_zone_offset">%2$s</xliff:g>)</string> + <!-- Date/Time picker dialogs strings --> <!-- The title of the time picker dialog. [CHAR LIMIT=NONE] --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d20b95f59b0c..f89ca44cce30 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -575,6 +575,7 @@ <java-symbol type="dimen" name="notification_top_pad_large_text" /> <java-symbol type="dimen" name="notification_top_pad_large_text_narrow" /> <java-symbol type="dimen" name="notification_badge_size" /> + <java-symbol type="dimen" name="notification_2025_badge_size" /> <java-symbol type="dimen" name="immersive_mode_cling_width" /> <java-symbol type="dimen" name="accessibility_magnification_indicator_width" /> <java-symbol type="dimen" name="circular_display_mask_thickness" /> @@ -2377,6 +2378,9 @@ <java-symbol type="string" name="config_secondaryLocationTimeZoneProviderPackageName" /> <java-symbol type="bool" name="config_enableTelephonyTimeZoneDetection" /> <java-symbol type="bool" name="config_supportTelephonyTimeZoneFallback" /> + <java-symbol type="bool" name="config_enableTimeZoneNotificationsSupported" /> + <java-symbol type="bool" name="config_enableTimeZoneNotificationsTrackingSupported" /> + <java-symbol type="bool" name="config_enableTimeZoneManualChangeTrackingSupported" /> <java-symbol type="bool" name="config_autoResetAirplaneMode" /> <java-symbol type="string" name="config_notificationAccessConfirmationActivity" /> <java-symbol type="bool" name="config_preventImeStartupUnlessTextEditor" /> @@ -4025,6 +4029,7 @@ <java-symbol type="string" name="notification_channel_network_available" /> <java-symbol type="array" name="config_defaultCloudSearchServices" /> <java-symbol type="string" name="notification_channel_vpn" /> + <java-symbol type="string" name="notification_channel_system_time" /> <java-symbol type="string" name="notification_channel_device_admin" /> <java-symbol type="string" name="notification_channel_alerts" /> <java-symbol type="string" name="notification_channel_retail_mode" /> @@ -4035,6 +4040,8 @@ <java-symbol type="string" name="notification_channel_accessibility_hearing_device" /> <java-symbol type="string" name="notification_channel_accessibility_security_policy" /> <java-symbol type="string" name="notification_channel_display" /> + <java-symbol type="string" name="time_zone_change_notification_title" /> + <java-symbol type="string" name="time_zone_change_notification_body" /> <java-symbol type="string" name="config_defaultAutofillService" /> <java-symbol type="string" name="config_defaultFieldClassificationService" /> <java-symbol type="string" name="config_defaultOnDeviceSpeechRecognitionService" /> diff --git a/core/tests/timetests/src/android/app/time/TimeZoneCapabilitiesTest.java b/core/tests/timetests/src/android/app/time/TimeZoneCapabilitiesTest.java index e368d2815855..cb8b5ce245b6 100644 --- a/core/tests/timetests/src/android/app/time/TimeZoneCapabilitiesTest.java +++ b/core/tests/timetests/src/android/app/time/TimeZoneCapabilitiesTest.java @@ -48,12 +48,14 @@ public class TimeZoneCapabilitiesTest { .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED) .setUseLocationEnabled(true) .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED) - .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED); + .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_POSSESSED); TimeZoneCapabilities.Builder builder2 = new TimeZoneCapabilities.Builder(TEST_USER_HANDLE) .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED) .setUseLocationEnabled(true) .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED) - .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED); + .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_POSSESSED); { TimeZoneCapabilities one = builder1.build(); TimeZoneCapabilities two = builder2.build(); @@ -115,6 +117,13 @@ public class TimeZoneCapabilitiesTest { TimeZoneCapabilities two = builder2.build(); assertEquals(one, two); } + + builder1.setConfigureNotificationsEnabledCapability(CAPABILITY_NOT_ALLOWED); + { + TimeZoneCapabilities one = builder1.build(); + TimeZoneCapabilities two = builder2.build(); + assertNotEquals(one, two); + } } @Test @@ -123,7 +132,8 @@ public class TimeZoneCapabilitiesTest { .setConfigureAutoDetectionEnabledCapability(CAPABILITY_POSSESSED) .setUseLocationEnabled(true) .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED) - .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED); + .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_POSSESSED); assertRoundTripParcelable(builder.build()); builder.setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED); @@ -137,6 +147,9 @@ public class TimeZoneCapabilitiesTest { builder.setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED); assertRoundTripParcelable(builder.build()); + + builder.setConfigureNotificationsEnabledCapability(CAPABILITY_NOT_ALLOWED); + assertRoundTripParcelable(builder.build()); } @Test @@ -151,6 +164,7 @@ public class TimeZoneCapabilitiesTest { .setUseLocationEnabled(true) .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED) .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_POSSESSED) .build(); TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder() @@ -175,6 +189,7 @@ public class TimeZoneCapabilitiesTest { .setUseLocationEnabled(true) .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED) .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_NOT_ALLOWED) .build(); TimeZoneConfiguration configChange = new TimeZoneConfiguration.Builder() @@ -191,6 +206,7 @@ public class TimeZoneCapabilitiesTest { .setUseLocationEnabled(true) .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED) .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_NOT_ALLOWED) .build(); { @@ -204,6 +220,7 @@ public class TimeZoneCapabilitiesTest { .setUseLocationEnabled(true) .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED) .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_NOT_ALLOWED) .build(); assertThat(updatedCapabilities).isEqualTo(expectedCapabilities); @@ -221,6 +238,7 @@ public class TimeZoneCapabilitiesTest { .setUseLocationEnabled(false) .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED) .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_NOT_ALLOWED) .build(); assertThat(updatedCapabilities).isEqualTo(expectedCapabilities); @@ -238,6 +256,7 @@ public class TimeZoneCapabilitiesTest { .setUseLocationEnabled(true) .setConfigureGeoDetectionEnabledCapability(CAPABILITY_POSSESSED) .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_NOT_ALLOWED) .build(); assertThat(updatedCapabilities).isEqualTo(expectedCapabilities); @@ -255,6 +274,25 @@ public class TimeZoneCapabilitiesTest { .setUseLocationEnabled(true) .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED) .setSetManualTimeZoneCapability(CAPABILITY_POSSESSED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_NOT_ALLOWED) + .build(); + + assertThat(updatedCapabilities).isEqualTo(expectedCapabilities); + } + + { + TimeZoneCapabilities updatedCapabilities = + new TimeZoneCapabilities.Builder(capabilities) + .setConfigureNotificationsEnabledCapability(CAPABILITY_POSSESSED) + .build(); + + TimeZoneCapabilities expectedCapabilities = + new TimeZoneCapabilities.Builder(TEST_USER_HANDLE) + .setConfigureAutoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED) + .setUseLocationEnabled(true) + .setConfigureGeoDetectionEnabledCapability(CAPABILITY_NOT_ALLOWED) + .setSetManualTimeZoneCapability(CAPABILITY_NOT_ALLOWED) + .setConfigureNotificationsEnabledCapability(CAPABILITY_POSSESSED) .build(); assertThat(updatedCapabilities).isEqualTo(expectedCapabilities); diff --git a/core/tests/timetests/src/android/app/time/TimeZoneConfigurationTest.java b/core/tests/timetests/src/android/app/time/TimeZoneConfigurationTest.java index 4ad3e41383aa..345e91268253 100644 --- a/core/tests/timetests/src/android/app/time/TimeZoneConfigurationTest.java +++ b/core/tests/timetests/src/android/app/time/TimeZoneConfigurationTest.java @@ -43,9 +43,11 @@ public class TimeZoneConfigurationTest { TimeZoneConfiguration completeConfig = new TimeZoneConfiguration.Builder() .setAutoDetectionEnabled(true) .setGeoDetectionEnabled(true) + .setNotificationsEnabled(true) .build(); assertTrue(completeConfig.isComplete()); assertTrue(completeConfig.hasIsGeoDetectionEnabled()); + assertTrue(completeConfig.hasIsNotificationsEnabled()); } @Test diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java index 4569cf31dab1..b9fccc1c4147 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationRunner.java @@ -106,11 +106,12 @@ public class BackAnimationRunner { private Runnable mFinishedCallback; private RemoteAnimationTarget[] mApps; - private IRemoteAnimationFinishedCallback mRemoteCallback; + private RemoteAnimationFinishedStub mRemoteCallback; private static class RemoteAnimationFinishedStub extends IRemoteAnimationFinishedCallback.Stub { //the binder callback should not hold strong reference to it to avoid memory leak. - private WeakReference<BackAnimationRunner> mRunnerRef; + private final WeakReference<BackAnimationRunner> mRunnerRef; + private boolean mAbandoned; private RemoteAnimationFinishedStub(BackAnimationRunner runner) { mRunnerRef = new WeakReference<>(runner); @@ -118,23 +119,29 @@ public class BackAnimationRunner { @Override public void onAnimationFinished() { - BackAnimationRunner runner = mRunnerRef.get(); + synchronized (this) { + if (mAbandoned) { + return; + } + } + final BackAnimationRunner runner = mRunnerRef.get(); if (runner == null) { return; } - if (runner.shouldMonitorCUJ(runner.mApps)) { - InteractionJankMonitor.getInstance().end(runner.mCujType); - } + runner.onAnimationFinish(this); + } - runner.mFinishedCallback.run(); - for (int i = runner.mApps.length - 1; i >= 0; --i) { - SurfaceControl sc = runner.mApps[i].leash; - if (sc != null && sc.isValid()) { - sc.release(); - } + void abandon() { + synchronized (this) { + mAbandoned = true; + final BackAnimationRunner runner = mRunnerRef.get(); + if (runner == null) { + return; + } + if (runner.shouldMonitorCUJ(runner.mApps)) { + InteractionJankMonitor.getInstance().end(runner.mCujType); + } } - runner.mApps = null; - runner.mFinishedCallback = null; } } @@ -144,13 +151,16 @@ public class BackAnimationRunner { */ void startAnimation(RemoteAnimationTarget[] apps, RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps, Runnable finishedCallback) { - InteractionJankMonitor interactionJankMonitor = InteractionJankMonitor.getInstance(); + if (mRemoteCallback != null) { + mRemoteCallback.abandon(); + mRemoteCallback = null; + } + mRemoteCallback = new RemoteAnimationFinishedStub(this); mFinishedCallback = finishedCallback; mApps = apps; - if (mRemoteCallback == null) mRemoteCallback = new RemoteAnimationFinishedStub(this); mWaitingAnimation = false; if (shouldMonitorCUJ(apps)) { - interactionJankMonitor.begin( + InteractionJankMonitor.getInstance().begin( apps[0].leash, mContext, mHandler, mCujType); } try { @@ -161,6 +171,28 @@ public class BackAnimationRunner { } } + void onAnimationFinish(RemoteAnimationFinishedStub finished) { + mHandler.post(() -> { + if (mRemoteCallback != null && finished != mRemoteCallback) { + return; + } + if (shouldMonitorCUJ(mApps)) { + InteractionJankMonitor.getInstance().end(mCujType); + } + + mFinishedCallback.run(); + for (int i = mApps.length - 1; i >= 0; --i) { + final SurfaceControl sc = mApps[i].leash; + if (sc != null && sc.isValid()) { + sc.release(); + } + } + mApps = null; + mFinishedCallback = null; + mRemoteCallback = null; + }); + } + @VisibleForTesting boolean shouldMonitorCUJ(RemoteAnimationTarget[] apps) { return apps.length > 0 && mCujType != NO_CUJ; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java index b796b411dd1a..1323fe0fa9ca 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java @@ -20,7 +20,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.ActivityManager.RunningTaskInfo; import android.app.TaskInfo; import android.content.ComponentName; import android.content.Context; @@ -60,7 +59,6 @@ import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import com.android.wm.shell.sysui.KeyguardChangeListener; 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.Transitions; import dagger.Lazy; @@ -73,6 +71,7 @@ import java.util.Optional; import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.IntPredicate; import java.util.function.Predicate; /** @@ -198,9 +197,6 @@ public class CompatUIController implements OnDisplaysChangedListener, private final CompatUIStatusManager mCompatUIStatusManager; @NonNull - private final FocusTransitionObserver mFocusTransitionObserver; - - @NonNull private final Optional<DesktopUserRepositories> mDesktopUserRepositories; public CompatUIController(@NonNull Context context, @@ -217,8 +213,7 @@ public class CompatUIController implements OnDisplaysChangedListener, @NonNull CompatUIShellCommandHandler compatUIShellCommandHandler, @NonNull AccessibilityManager accessibilityManager, @NonNull CompatUIStatusManager compatUIStatusManager, - @NonNull Optional<DesktopUserRepositories> desktopUserRepositories, - @NonNull FocusTransitionObserver focusTransitionObserver) { + @NonNull Optional<DesktopUserRepositories> desktopUserRepositories) { mContext = context; mShellController = shellController; mDisplayController = displayController; @@ -235,7 +230,6 @@ public class CompatUIController implements OnDisplaysChangedListener, DISAPPEAR_DELAY_MS, flags); mCompatUIStatusManager = compatUIStatusManager; mDesktopUserRepositories = desktopUserRepositories; - mFocusTransitionObserver = focusTransitionObserver; shellInit.addInitCallback(this::onInit, this); } @@ -412,8 +406,7 @@ public class CompatUIController implements OnDisplaysChangedListener, // start tracking the buttons visibility for this task. if (mTopActivityTaskId != taskInfo.taskId && !taskInfo.isTopActivityTransparent - && taskInfo.isVisible - && mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)) { + && taskInfo.isVisible && taskInfo.isFocused) { mTopActivityTaskId = taskInfo.taskId; setHasShownUserAspectRatioSettingsButton(false); } 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 2600bcc18f72..23a0f4adb6d2 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 @@ -272,8 +272,7 @@ public abstract class WMShellBaseModule { @NonNull CompatUIState compatUIState, @NonNull CompatUIComponentIdGenerator componentIdGenerator, @NonNull CompatUIComponentFactory compatUIComponentFactory, - CompatUIStatusManager compatUIStatusManager, - @NonNull FocusTransitionObserver focusTransitionObserver) { + CompatUIStatusManager compatUIStatusManager) { if (!context.getResources().getBoolean(R.bool.config_enableCompatUIController)) { return Optional.empty(); } @@ -298,8 +297,7 @@ public abstract class WMShellBaseModule { compatUIShellCommandHandler.get(), accessibilityManager.get(), compatUIStatusManager, - desktopUserRepositories, - focusTransitionObserver)); + desktopUserRepositories)); } @WMSingleton diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java index 784e1907894d..b5c9fa151dac 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java @@ -62,11 +62,12 @@ import com.android.wm.shell.desktopmode.DesktopRepository; import com.android.wm.shell.desktopmode.DesktopUserRepositories; 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.Transitions; import dagger.Lazy; +import java.util.Optional; + import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -76,8 +77,6 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.Optional; - /** * Tests for {@link CompatUIController}. * @@ -128,8 +127,6 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { private DesktopUserRepositories mDesktopUserRepositories; @Mock private DesktopRepository mDesktopRepository; - @Mock - private FocusTransitionObserver mFocusTransitionObserver; @Captor ArgumentCaptor<OnInsetsChangedListener> mOnInsetsChangedListenerCaptor; @@ -165,8 +162,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { mMockDisplayController, mMockDisplayInsetsController, mMockImeController, mMockSyncQueue, mMockExecutor, mMockTransitionsLazy, mDockStateReader, mCompatUIConfiguration, mCompatUIShellCommandHandler, mAccessibilityManager, - mCompatUIStatusManager, Optional.of(mDesktopUserRepositories), - mFocusTransitionObserver) { + mCompatUIStatusManager, Optional.of(mDesktopUserRepositories)) { @Override CompatUIWindowManager createCompatUiWindowManager(Context context, TaskInfo taskInfo, ShellTaskOrganizer.TaskListener taskListener) { @@ -284,7 +280,6 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { doReturn(false).when(mMockRestartDialogLayout).updateCompatInfo(any(), any(), anyBoolean()); TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); verify(mController).createCompatUiWindowManager(any(), eq(taskInfo), eq(mMockTaskListener)); @@ -416,7 +411,6 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Verify button remains hidden while IME is showing. TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ false); @@ -449,7 +443,6 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Verify button remains hidden while keyguard is showing. TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); verify(mMockCompatLayout).updateCompatInfo(taskInfo, mMockTaskListener, /* canShow= */ false); @@ -530,7 +523,6 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testRestartLayoutRecreatedIfNeeded() { final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); doReturn(true).when(mMockRestartDialogLayout) .needsToBeRecreated(any(TaskInfo.class), any(ShellTaskOrganizer.TaskListener.class)); @@ -546,7 +538,6 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { @RequiresFlagsDisabled(Flags.FLAG_APP_COMPAT_UI_FRAMEWORK) public void testRestartLayoutNotRecreatedIfNotNeeded() { final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); doReturn(false).when(mMockRestartDialogLayout) .needsToBeRecreated(any(TaskInfo.class), any(ShellTaskOrganizer.TaskListener.class)); @@ -567,8 +558,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Create new task final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - /* isVisible */ true); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); + /* isVisible */ true, /* isFocused */ true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo); @@ -584,8 +574,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testUpdateActiveTaskInfo_newTask_notVisibleOrFocused_notUpdated() { // Create new task final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - /* isVisible */ true); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); + /* isVisible */ true, /* isFocused */ true); // Simulate task being shown mController.updateActiveTaskInfo(taskInfo); @@ -603,8 +592,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Create visible but NOT focused task final TaskInfo taskInfo1 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, - /* isVisible */ true); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); + /* isVisible */ true, /* isFocused */ false); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo1); @@ -616,8 +604,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Create focused but NOT visible task final TaskInfo taskInfo2 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, - /* isVisible */ false); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); + /* isVisible */ false, /* isFocused */ true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo2); @@ -629,8 +616,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Create NOT focused but NOT visible task final TaskInfo taskInfo3 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, - /* isVisible */ false); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); + /* isVisible */ false, /* isFocused */ false); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo3); @@ -646,8 +632,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testUpdateActiveTaskInfo_sameTask_notUpdated() { // Create new task final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - /* isVisible */ true); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); + /* isVisible */ true, /* isFocused */ true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo); @@ -675,8 +660,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testUpdateActiveTaskInfo_transparentTask_notUpdated() { // Create new task final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true, - /* isVisible */ true); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); + /* isVisible */ true, /* isFocused */ true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo); @@ -694,8 +678,7 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { // Create transparent task final TaskInfo taskInfo1 = createTaskInfo(DISPLAY_ID, newTaskId, /* hasSizeCompat= */ true, - /* isVisible */ true, /* isTopActivityTransparent */ true); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(true); + /* isVisible */ true, /* isFocused */ true, /* isTopActivityTransparent */ true); // Simulate new task being shown mController.updateActiveTaskInfo(taskInfo1); @@ -711,7 +694,6 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testLetterboxEduLayout_notCreatedWhenLetterboxEducationIsDisabled() { TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); taskInfo.appCompatTaskInfo.setLetterboxEducationEnabled(false); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); @@ -725,7 +707,6 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testUpdateActiveTaskInfo_removeAllComponentWhenInDesktopModeFlagEnabled() { TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(0); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); @@ -744,7 +725,6 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { public void testUpdateActiveTaskInfo_removeAllComponentWhenInDesktopModeFlagDisabled() { when(mDesktopUserRepositories.getCurrent().getVisibleTaskCount(DISPLAY_ID)).thenReturn(0); TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID, /* hasSizeCompat= */ true); - when(mFocusTransitionObserver.hasGlobalFocus((RunningTaskInfo) taskInfo)).thenReturn(false); mController.onCompatInfoChanged(new CompatUIInfo(taskInfo, mMockTaskListener)); @@ -759,22 +739,23 @@ public class CompatUIControllerTest extends CompatUIShellTestCase { private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat) { return createTaskInfo(displayId, taskId, hasSizeCompat, /* isVisible */ false, - /* isTopActivityTransparent */ false); + /* isFocused */ false, /* isTopActivityTransparent */ false); } private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat, - boolean isVisible) { + boolean isVisible, boolean isFocused) { return createTaskInfo(displayId, taskId, hasSizeCompat, - isVisible, /* isTopActivityTransparent */ false); + isVisible, isFocused, /* isTopActivityTransparent */ false); } private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat, - boolean isVisible, boolean isTopActivityTransparent) { + boolean isVisible, boolean isFocused, boolean isTopActivityTransparent) { RunningTaskInfo taskInfo = new RunningTaskInfo(); taskInfo.taskId = taskId; taskInfo.displayId = displayId; taskInfo.appCompatTaskInfo.setTopActivityInSizeCompat(hasSizeCompat); taskInfo.isVisible = isVisible; + taskInfo.isFocused = isFocused; taskInfo.isTopActivityTransparent = isTopActivityTransparent; taskInfo.appCompatTaskInfo.setLetterboxEducationEnabled(true); taskInfo.appCompatTaskInfo.setTopActivityLetterboxed(true); diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java index 4125a81f9bbc..fc61b1e875f3 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/GlobalSettings.java @@ -46,6 +46,7 @@ public class GlobalSettings { Settings.Global.APP_AUTO_RESTRICTION_ENABLED, Settings.Global.AUTO_TIME, Settings.Global.AUTO_TIME_ZONE, + Settings.Global.TIME_ZONE_NOTIFICATIONS, Settings.Global.POWER_SOUNDS_ENABLED, Settings.Global.DOCK_SOUNDS_ENABLED, Settings.Global.CHARGING_SOUNDS_ENABLED, diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java index 32d4580f67ec..c0e266fa269f 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java @@ -102,6 +102,7 @@ public class GlobalSettingsValidators { }); VALIDATORS.put(Global.AUTO_TIME, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.AUTO_TIME_ZONE, BOOLEAN_VALIDATOR); + VALIDATORS.put(Global.TIME_ZONE_NOTIFICATIONS, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.POWER_SOUNDS_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.DOCK_SOUNDS_ENABLED, BOOLEAN_VALIDATOR); VALIDATORS.put(Global.CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index ef0bc3b100e0..f79a60f5be96 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -212,10 +212,6 @@ public class SettingsBackupAgent extends BackupAgentHelper { private static final String ERROR_IO_EXCEPTION = "io_exception"; private static final String ERROR_FAILED_TO_RESTORE_SOFTAP_CONFIG = "failed_to_restore_softap_config"; - private static final String ERROR_FAILED_TO_CONVERT_NETWORK_POLICIES = - "failed_to_convert_network_policies"; - private static final String ERROR_UNKNOWN_BACKUP_SERIALIZATION_VERSION = - "unknown_backup_serialization_version"; // Name of the temporary file we use during full backup/restore. This is @@ -1438,7 +1434,6 @@ public class SettingsBackupAgent extends BackupAgentHelper { try { out.writeInt(NETWORK_POLICIES_BACKUP_VERSION); out.writeInt(policies.length); - int numberOfPoliciesBackedUp = 0; for (NetworkPolicy policy : policies) { // We purposefully only backup policies that the user has // defined; any inferred policies might include @@ -1448,23 +1443,13 @@ public class SettingsBackupAgent extends BackupAgentHelper { out.writeByte(BackupUtils.NOT_NULL); out.writeInt(marshaledPolicy.length); out.write(marshaledPolicy); - if (areAgentMetricsEnabled) { - numberOfPoliciesBackedUp++; - } } else { out.writeByte(BackupUtils.NULL); } } - if (areAgentMetricsEnabled) { - numberOfSettingsPerKey.put(KEY_NETWORK_POLICIES, numberOfPoliciesBackedUp); - } } catch (IOException ioe) { Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage()); baos.reset(); - mBackupRestoreEventLogger.logItemsBackupFailed( - KEY_NETWORK_POLICIES, - policies.length, - ERROR_FAILED_TO_CONVERT_NETWORK_POLICIES); } } return baos.toByteArray(); @@ -1498,10 +1483,6 @@ public class SettingsBackupAgent extends BackupAgentHelper { try { int version = in.readInt(); if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) { - mBackupRestoreEventLogger.logItemsRestoreFailed( - KEY_NETWORK_POLICIES, - /* count= */ 1, - ERROR_UNKNOWN_BACKUP_SERIALIZATION_VERSION); throw new BackupUtils.BadVersionException( "Unknown Backup Serialization Version"); } @@ -1518,15 +1499,10 @@ public class SettingsBackupAgent extends BackupAgentHelper { } // Only set the policies if there was no error in the restore operation networkPolicyManager.setNetworkPolicies(policies); - mBackupRestoreEventLogger.logItemsRestored(KEY_NETWORK_POLICIES, policies.length); } catch (NullPointerException | IOException | BackupUtils.BadVersionException | DateTimeException e) { // NPE can be thrown when trying to instantiate a NetworkPolicy Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage()); - mBackupRestoreEventLogger.logItemsRestoreFailed( - KEY_NETWORK_POLICIES, - /* count= */ 1, - ERROR_FAILED_TO_CONVERT_NETWORK_POLICIES); } } } diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt index 912633c874ed..e6fbc725af04 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManagerTest.kt @@ -101,7 +101,6 @@ class RenderStageManagerTest : SysuiTestCase() { // VERIFY that the renderer is not queried for group or row controllers inOrder(spyViewRenderer).apply { verify(spyViewRenderer, times(1)).onRenderList(any()) - verify(spyViewRenderer, times(1)).getStackController() verify(spyViewRenderer, never()).getGroupController(any()) verify(spyViewRenderer, never()).getRowController(any()) verify(spyViewRenderer, times(1)).onDispatchComplete() @@ -121,7 +120,6 @@ class RenderStageManagerTest : SysuiTestCase() { // VERIFY that the renderer is queried once per group/entry inOrder(spyViewRenderer).apply { verify(spyViewRenderer, times(1)).onRenderList(any()) - verify(spyViewRenderer, times(1)).getStackController() verify(spyViewRenderer, times(2)).getGroupController(any()) verify(spyViewRenderer, times(8)).getRowController(any()) verify(spyViewRenderer, times(1)).onDispatchComplete() @@ -144,7 +142,6 @@ class RenderStageManagerTest : SysuiTestCase() { // VERIFY that the renderer is queried once per group/entry inOrder(spyViewRenderer).apply { verify(spyViewRenderer, times(1)).onRenderList(any()) - verify(spyViewRenderer, times(1)).getStackController() verify(spyViewRenderer, times(2)).getGroupController(any()) verify(spyViewRenderer, times(8)).getRowController(any()) verify(spyViewRenderer, times(1)).onDispatchComplete() @@ -162,7 +159,7 @@ class RenderStageManagerTest : SysuiTestCase() { onRenderListListener.onRenderList(listWith2Groups8Entries()) // VERIFY that the listeners are invoked once per group and once per entry - verify(onAfterRenderListListener, times(1)).onAfterRenderList(any(), any()) + verify(onAfterRenderListListener, times(1)).onAfterRenderList(any()) verify(onAfterRenderGroupListener, times(2)).onAfterRenderGroup(any(), any()) verify(onAfterRenderEntryListener, times(8)).onAfterRenderEntry(any(), any()) verifyNoMoreInteractions( @@ -182,7 +179,7 @@ class RenderStageManagerTest : SysuiTestCase() { onRenderListListener.onRenderList(listOf()) // VERIFY that the stack listener is invoked once but other listeners are not - verify(onAfterRenderListListener, times(1)).onAfterRenderList(any(), any()) + verify(onAfterRenderListListener, times(1)).onAfterRenderList(any()) verify(onAfterRenderGroupListener, never()).onAfterRenderGroup(any(), any()) verify(onAfterRenderEntryListener, never()).onAfterRenderEntry(any(), any()) verifyNoMoreInteractions( @@ -203,8 +200,6 @@ class RenderStageManagerTest : SysuiTestCase() { private class FakeNotifViewRenderer : NotifViewRenderer { override fun onRenderList(notifList: List<ListEntry>) {} - override fun getStackController(): NotifStackController = mock() - override fun getGroupController(group: GroupEntry): NotifGroupController = mock() override fun getRowController(entry: NotificationEntry): NotifRowController = mock() diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorTest.kt index 54ce88b40c11..83c61507a506 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractorTest.kt @@ -26,7 +26,7 @@ import com.android.systemui.SysuiTestCase import com.android.systemui.coroutines.collectLastValue import com.android.systemui.kosmos.testScope import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips -import com.android.systemui.statusbar.notification.collection.render.NotifStats +import com.android.systemui.statusbar.notification.data.model.NotifStats import com.android.systemui.statusbar.notification.data.model.activeNotificationModel import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository @@ -275,7 +275,6 @@ class ActiveNotificationsInteractorTest : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = true, hasNonClearableSilentNotifs = false, @@ -293,7 +292,6 @@ class ActiveNotificationsInteractorTest : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = false, @@ -311,7 +309,6 @@ class ActiveNotificationsInteractorTest : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 0, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = false, @@ -329,7 +326,6 @@ class ActiveNotificationsInteractorTest : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = false, @@ -347,7 +343,6 @@ class ActiveNotificationsInteractorTest : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = true, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = true, @@ -365,7 +360,6 @@ class ActiveNotificationsInteractorTest : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = true, hasNonClearableSilentNotifs = false, @@ -383,7 +377,6 @@ class ActiveNotificationsInteractorTest : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = true, @@ -401,7 +394,6 @@ class ActiveNotificationsInteractorTest : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = false, diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt index 06b1c432955a..b3a60b052d08 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt @@ -37,7 +37,7 @@ import com.android.systemui.power.shared.model.WakefulnessState import com.android.systemui.res.R import com.android.systemui.shade.shadeTestUtil import com.android.systemui.shared.settings.data.repository.fakeSecureSettingsRepository -import com.android.systemui.statusbar.notification.collection.render.NotifStats +import com.android.systemui.statusbar.notification.data.model.NotifStats import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix import com.android.systemui.statusbar.notification.footer.shared.NotifRedesignFooter @@ -115,7 +115,6 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = true, hasNonClearableSilentNotifs = false, @@ -133,7 +132,6 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = false, @@ -151,7 +149,6 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = true, hasNonClearableSilentNotifs = false, @@ -183,7 +180,6 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { // AND there are clearable notifications activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = true, hasNonClearableSilentNotifs = false, @@ -217,7 +213,6 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() { // AND there are clearable notifications activeNotificationListRepository.notifStats.value = NotifStats( - numActiveNotifs = 2, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = true, hasNonClearableSilentNotifs = false, diff --git a/packages/SystemUI/proguard_common.flags b/packages/SystemUI/proguard_common.flags index 162d8aebfc62..02b2bcf8e40d 100644 --- a/packages/SystemUI/proguard_common.flags +++ b/packages/SystemUI/proguard_common.flags @@ -1,5 +1,11 @@ -include proguard_kotlin.flags --keep class com.android.systemui.VendorServices + +# VendorServices implements CoreStartable and may be instantiated reflectively in +# SystemUIApplication#startAdditionalStartable. +# TODO(b/373579455): Rewrite this to a @UsesReflection keep annotation. +-keep class com.android.systemui.VendorServices { + public void <init>(); +} # Needed to ensure callback field references are kept in their respective # owning classes when the downstream callback registrars only store weak refs. diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index a01ff3d5258f..d445ed927a25 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -3919,6 +3919,16 @@ The helper is a component that shows the user which keyboard shortcuts they can use. [CHAR LIMIT=NONE] --> <string name="shortcut_helper_plus_symbol">+</string> + <!-- Accessibility label for the plus icon on a shortcut in shortcut helper that allows the user + to add a new custom shortcut. + The helper is a component that shows the user which keyboard shortcuts they can use. + [CHAR LIMIT=NONE] --> + <string name="shortcut_helper_add_shortcut_button_label">Add shortcut</string> + <!-- Accessibility label for the bin(trash) icon on a shortcut in shortcut helper that allows the + user to delete an existing custom shortcut. + The helper is a component that shows the user which keyboard shortcuts they can use. + [CHAR LIMIT=NONE] --> + <string name="shortcut_helper_delete_shortcut_button_label">Delete shortcut</string> <!-- Keyboard touchpad tutorial scheduler--> <!-- Notification title for launching keyboard tutorial [CHAR_LIMIT=100] --> 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 aea583d67289..ba31d08c9c1b 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 @@ -729,6 +729,7 @@ private fun AddShortcutButton(onClick: () -> Unit) { contentColor = MaterialTheme.colorScheme.primary, contentPaddingVertical = 0.dp, contentPaddingHorizontal = 0.dp, + contentDescription = stringResource(R.string.shortcut_helper_add_shortcut_button_label), ) } @@ -749,6 +750,7 @@ private fun DeleteShortcutButton(onClick: () -> Unit) { contentColor = MaterialTheme.colorScheme.primary, contentPaddingVertical = 0.dp, contentPaddingHorizontal = 0.dp, + contentDescription = stringResource(R.string.shortcut_helper_delete_shortcut_button_label), ) } diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt index 55c0fe297bcb..9a380f495176 100644 --- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt +++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/Surfaces.kt @@ -230,6 +230,7 @@ fun ShortcutHelperButton( contentPaddingVertical: Dp = 10.dp, enabled: Boolean = true, border: BorderStroke? = null, + contentDescription: String? = null, ) { ShortcutHelperButtonSurface( onClick = onClick, @@ -254,8 +255,7 @@ fun ShortcutHelperButton( Icon( tint = contentColor, imageVector = iconSource.imageVector, - contentDescription = - null, // TODO this probably should not be null for accessibility. + contentDescription = contentDescription, modifier = Modifier.size(20.dp).wrapContentSize(Alignment.Center), ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt index 90212ed5b5f7..034a4fd2af72 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinator.kt @@ -36,7 +36,7 @@ class DataStoreCoordinator internal constructor(private val notifLiveDataStoreImpl: NotifLiveDataStoreImpl) : CoreCoordinator { override fun attach(pipeline: NotifPipeline) { - pipeline.addOnAfterRenderListListener { entries, _ -> onAfterRenderList(entries) } + pipeline.addOnAfterRenderListListener { entries -> onAfterRenderList(entries) } } override fun dumpPipeline(d: PipelineDumper) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt index d4d3cdf42fb1..1cb2366a16fe 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt @@ -23,8 +23,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl -import com.android.systemui.statusbar.notification.collection.render.NotifStackController -import com.android.systemui.statusbar.notification.collection.render.NotifStats +import com.android.systemui.statusbar.notification.data.model.NotifStats import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.RenderNotificationListInteractor import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT @@ -51,8 +50,7 @@ internal constructor( groupExpansionManagerImpl.attach(pipeline) } - // TODO: b/293167744 - Remove controller param. - private fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) = + private fun onAfterRenderList(entries: List<ListEntry>) = traceSection("StackCoordinator.onAfterRenderList") { val notifStats = calculateNotifStats(entries) activeNotificationsInteractor.setNotifStats(notifStats) @@ -84,7 +82,6 @@ internal constructor( } } return NotifStats( - numActiveNotifs = entries.size, hasNonClearableAlertingNotifs = hasNonClearableAlertingNotifs, hasClearableAlertingNotifs = hasClearableAlertingNotifs, hasNonClearableSilentNotifs = hasNonClearableSilentNotifs, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java index a34d033afcaa..c58b3febe54b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NotifPipelineInitializer.java @@ -33,7 +33,6 @@ import com.android.systemui.statusbar.notification.collection.ShadeListBuilder; import com.android.systemui.statusbar.notification.collection.coalescer.GroupCoalescer; import com.android.systemui.statusbar.notification.collection.coordinator.NotifCoordinators; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; -import com.android.systemui.statusbar.notification.collection.render.NotifStackController; import com.android.systemui.statusbar.notification.collection.render.RenderStageManager; import com.android.systemui.statusbar.notification.collection.render.ShadeViewManager; import com.android.systemui.statusbar.notification.collection.render.ShadeViewManagerFactory; @@ -89,8 +88,7 @@ public class NotifPipelineInitializer implements Dumpable, PipelineDumpable { public void initialize( NotificationListener notificationService, NotificationRowBinderImpl rowBinder, - NotificationListContainer listContainer, - NotifStackController stackController) { + NotificationListContainer listContainer) { mDumpManager.registerDumpable("NotifPipeline", this); mNotificationService = notificationService; @@ -102,7 +100,7 @@ public class NotifPipelineInitializer implements Dumpable, PipelineDumpable { mNotifPluggableCoordinators.attach(mPipelineWrapper); // Wire up pipeline - mShadeViewManager = mShadeViewManagerFactory.create(listContainer, stackController); + mShadeViewManager = mShadeViewManagerFactory.create(listContainer); mShadeViewManager.attach(mRenderStageManager); mRenderStageManager.attach(mListBuilder); mListBuilder.attach(mNotifCollection); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnAfterRenderListListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnAfterRenderListListener.java index b5a0f7ae169d..ac450c03b850 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnAfterRenderListListener.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnAfterRenderListListener.java @@ -20,7 +20,6 @@ import androidx.annotation.NonNull; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotifPipeline; -import com.android.systemui.statusbar.notification.collection.render.NotifStackController; import java.util.List; @@ -31,9 +30,6 @@ public interface OnAfterRenderListListener { * * @param entries The current list of top-level entries. Note that this is a live view into the * current list and will change whenever the pipeline is rerun. - * @param controller An object for setting state on the shade. */ - void onAfterRenderList( - @NonNull List<ListEntry> entries, - @NonNull NotifStackController controller); + void onAfterRenderList(@NonNull List<ListEntry> entries); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifStackController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifStackController.kt deleted file mode 100644 index a37937a6c495..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifStackController.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.notification.collection.render - -import javax.inject.Inject - -/** An interface by which the pipeline can make updates to the notification root view. */ -interface NotifStackController { - /** Provides stats about the list of notifications attached to the shade */ - fun setNotifStats(stats: NotifStats) -} - -/** Data provided to the NotificationRootController whenever the pipeline runs */ -data class NotifStats( - // TODO(b/293167744): The count can be removed from here when we remove the FooterView flag. - val numActiveNotifs: Int, - val hasNonClearableAlertingNotifs: Boolean, - val hasClearableAlertingNotifs: Boolean, - val hasNonClearableSilentNotifs: Boolean, - val hasClearableSilentNotifs: Boolean -) { - companion object { - @JvmStatic val empty = NotifStats(0, false, false, false, false) - } -} - -/** - * An implementation of NotifStackController which provides default, no-op implementations of each - * method. This is used by ArcSystemUI so that that implementation can opt-in to overriding methods, - * rather than forcing us to add no-op implementations in their implementation every time a method - * is added. - */ -open class DefaultNotifStackController @Inject constructor() : NotifStackController { - override fun setNotifStats(stats: NotifStats) {} -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt index 410b78b9d3bf..8284022c7270 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewRenderer.kt @@ -37,12 +37,6 @@ interface NotifViewRenderer { fun onRenderList(notifList: List<ListEntry>) /** - * Provides an interface for the pipeline to update the overall shade. This will be called at - * most once for each time [onRenderList] is called. - */ - fun getStackController(): NotifStackController - - /** * Provides an interface for the pipeline to update individual groups. This will be called at * most once for each group in the most recent call to [onRenderList]. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt index 9d3b098fa966..21e68376031c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RenderStageManager.kt @@ -50,7 +50,7 @@ class RenderStageManager @Inject constructor() : PipelineDumpable { traceSection("RenderStageManager.onRenderList") { val viewRenderer = viewRenderer ?: return viewRenderer.onRenderList(notifList) - dispatchOnAfterRenderList(viewRenderer, notifList) + dispatchOnAfterRenderList(notifList) dispatchOnAfterRenderGroups(viewRenderer, notifList) dispatchOnAfterRenderEntries(viewRenderer, notifList) viewRenderer.onDispatchComplete() @@ -85,15 +85,9 @@ class RenderStageManager @Inject constructor() : PipelineDumpable { dump("onAfterRenderEntryListeners", onAfterRenderEntryListeners) } - private fun dispatchOnAfterRenderList( - viewRenderer: NotifViewRenderer, - entries: List<ListEntry>, - ) { + private fun dispatchOnAfterRenderList(entries: List<ListEntry>) { traceSection("RenderStageManager.dispatchOnAfterRenderList") { - val stackController = viewRenderer.getStackController() - onAfterRenderListListeners.forEach { listener -> - listener.onAfterRenderList(entries, stackController) - } + onAfterRenderListListeners.forEach { listener -> listener.onAfterRenderList(entries) } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt index 3c838e5b707e..72316bf14c9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt @@ -41,7 +41,6 @@ class ShadeViewManager constructor( @ShadeDisplayAware context: Context, @Assisted listContainer: NotificationListContainer, - @Assisted private val stackController: NotifStackController, mediaContainerController: MediaContainerController, featureManager: NotificationSectionsFeatureManager, sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider, @@ -83,8 +82,6 @@ constructor( } } - override fun getStackController(): NotifStackController = stackController - override fun getGroupController(group: GroupEntry): NotifGroupController = viewBarn.requireGroupController(group.requireSummary) @@ -95,8 +92,5 @@ constructor( @AssistedFactory interface ShadeViewManagerFactory { - fun create( - listContainer: NotificationListContainer, - stackController: NotifStackController, - ): ShadeViewManager + fun create(listContainer: NotificationListContainer): ShadeViewManager } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/model/NotifStats.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/model/NotifStats.kt new file mode 100644 index 000000000000..d7fd7025a94f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/model/NotifStats.kt @@ -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 com.android.systemui.statusbar.notification.data.model + +/** Information about the current list of notifications. */ +data class NotifStats( + val hasNonClearableAlertingNotifs: Boolean, + val hasClearableAlertingNotifs: Boolean, + val hasNonClearableSilentNotifs: Boolean, + val hasClearableSilentNotifs: Boolean, +) { + companion object { + @JvmStatic + val empty = + NotifStats( + hasNonClearableAlertingNotifs = false, + hasClearableAlertingNotifs = false, + hasNonClearableSilentNotifs = false, + hasClearableSilentNotifs = false, + ) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt index 2b9e49372a63..70f06ebe8468 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/data/repository/ActiveNotificationListRepository.kt @@ -16,7 +16,7 @@ package com.android.systemui.statusbar.notification.data.repository import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.statusbar.notification.collection.render.NotifStats +import com.android.systemui.statusbar.notification.data.model.NotifStats import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore.Key import com.android.systemui.statusbar.notification.shared.ActiveNotificationEntryModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt index 6b93ee1c435e..0c040c855368 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/ActiveNotificationsInteractor.kt @@ -18,7 +18,7 @@ package com.android.systemui.statusbar.notification.domain.interactor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips -import com.android.systemui.statusbar.notification.collection.render.NotifStats +import com.android.systemui.statusbar.notification.data.model.NotifStats import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository import com.android.systemui.statusbar.notification.shared.ActiveNotificationGroupModel import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt index 2c5d9c2e449b..3c2051f0b153 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt @@ -20,7 +20,6 @@ import android.service.notification.StatusBarNotification import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption import com.android.systemui.statusbar.NotificationPresenter import com.android.systemui.statusbar.notification.NotificationActivityStarter -import com.android.systemui.statusbar.notification.collection.render.NotifStackController import com.android.systemui.statusbar.notification.stack.NotificationListContainer /** @@ -33,7 +32,6 @@ interface NotificationsController { fun initialize( presenter: NotificationPresenter, listContainer: NotificationListContainer, - stackController: NotifStackController, notificationActivityStarter: NotificationActivityStarter, ) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index ea6a60bd7a1c..0a9899e88d24 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -34,7 +34,6 @@ import com.android.systemui.statusbar.notification.collection.inflation.Notifica import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener -import com.android.systemui.statusbar.notification.collection.render.NotifStackController import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder import com.android.systemui.statusbar.notification.logging.NotificationLogger import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer @@ -76,7 +75,6 @@ constructor( override fun initialize( presenter: NotificationPresenter, listContainer: NotificationListContainer, - stackController: NotifStackController, notificationActivityStarter: NotificationActivityStarter, ) { notificationListener.registerAsSystemService() @@ -101,7 +99,7 @@ constructor( notifPipelineInitializer .get() - .initialize(notificationListener, notificationRowBinder, listContainer, stackController) + .initialize(notificationListener, notificationRowBinder, listContainer) targetSdkResolver.initialize(notifPipeline.get()) notificationsMediaManager.setUpWithPresenter(presenter) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt index 148b3f021643..92d96f9e899b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt @@ -21,7 +21,6 @@ import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.Snoo import com.android.systemui.statusbar.NotificationListener import com.android.systemui.statusbar.NotificationPresenter import com.android.systemui.statusbar.notification.NotificationActivityStarter -import com.android.systemui.statusbar.notification.collection.render.NotifStackController import com.android.systemui.statusbar.notification.stack.NotificationListContainer import javax.inject.Inject @@ -35,7 +34,6 @@ constructor(private val notificationListener: NotificationListener) : Notificati override fun initialize( presenter: NotificationPresenter, listContainer: NotificationListContainer, - stackController: NotifStackController, notificationActivityStarter: NotificationActivityStarter, ) { // Always connect the listener even if notification-handling is disabled. Being a listener diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index b892bebb3120..e752e6581421 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -103,9 +103,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.Di import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider; import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator; -import com.android.systemui.statusbar.notification.collection.render.DefaultNotifStackController; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; -import com.android.systemui.statusbar.notification.collection.render.NotifStackController; import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider; import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; import com.android.systemui.statusbar.notification.headsup.HeadsUpNotificationViewControllerEmptyImpl; @@ -211,9 +209,6 @@ public class NotificationStackScrollLayoutController implements Dumpable { private final NotificationListContainerImpl mNotificationListContainer = new NotificationListContainerImpl(); - // TODO: b/293167744 - Remove this. - private final NotifStackController mNotifStackController = - new DefaultNotifStackController(); @VisibleForTesting final View.OnAttachStateChangeListener mOnAttachStateChangeListener = @@ -1469,10 +1464,6 @@ public class NotificationStackScrollLayoutController implements Dumpable { return mNotificationListContainer; } - public NotifStackController getNotifStackController() { - return mNotifStackController; - } - public void resetCheckSnoozeLeavebehind() { mView.resetCheckSnoozeLeavebehind(); } 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 3d6cd7e49dfe..b146b92ed110 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -1492,7 +1492,6 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mNotificationsController.initialize( mPresenterLazy.get(), mNotifListContainer, - mStackScrollerController.getNotifStackController(), mNotificationActivityStarterLazy.get()); mWindowRootViewVisibilityInteractor.setUp(mPresenterLazy.get(), mNotificationsController); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt index a3c518128b47..f31d49094ac4 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/DataStoreCoordinatorTest.kt @@ -26,7 +26,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener -import com.android.systemui.statusbar.notification.collection.render.NotifStackController import com.android.systemui.util.mockito.withArgCaptor import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -48,7 +47,6 @@ class DataStoreCoordinatorTest : SysuiTestCase() { private val pipeline: NotifPipeline = mock() private val notifLiveDataStoreImpl: NotifLiveDataStoreImpl = mock() - private val stackController: NotifStackController = mock() private val section: NotifSection = mock() @Before @@ -63,7 +61,7 @@ class DataStoreCoordinatorTest : SysuiTestCase() { @Test fun testUpdateDataStore_withOneEntry() { - afterRenderListListener.onAfterRenderList(listOf(entry), stackController) + afterRenderListListener.onAfterRenderList(listOf(entry)) verify(notifLiveDataStoreImpl).setActiveNotifList(eq(listOf(entry))) verifyNoMoreInteractions(notifLiveDataStoreImpl) } @@ -86,8 +84,7 @@ class DataStoreCoordinatorTest : SysuiTestCase() { .setSection(section) .build(), notificationEntry("baz", 1), - ), - stackController, + ) ) val list: List<NotificationEntry> = withArgCaptor { verify(notifLiveDataStoreImpl).setActiveNotifList(capture()) @@ -111,7 +108,7 @@ class DataStoreCoordinatorTest : SysuiTestCase() { @Test fun testUpdateDataStore_withZeroEntries_whenNewPipelineEnabled() { - afterRenderListListener.onAfterRenderList(listOf(), stackController) + afterRenderListListener.onAfterRenderList(listOf()) verify(notifLiveDataStoreImpl).setActiveNotifList(eq(listOf())) verifyNoMoreInteractions(notifLiveDataStoreImpl) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt index 77bac59b9dcd..97e99b95f80e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinatorTest.kt @@ -28,8 +28,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection import com.android.systemui.statusbar.notification.collection.listbuilder.OnAfterRenderListListener import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl -import com.android.systemui.statusbar.notification.collection.render.NotifStackController -import com.android.systemui.statusbar.notification.collection.render.NotifStats +import com.android.systemui.statusbar.notification.data.model.NotifStats import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor import com.android.systemui.statusbar.notification.domain.interactor.RenderNotificationListInteractor import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow @@ -43,7 +42,6 @@ import org.junit.runner.RunWith import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.verify -import org.mockito.kotlin.verifyNoMoreInteractions import org.mockito.kotlin.whenever @SmallTest @@ -61,7 +59,6 @@ class StackCoordinatorTest : SysuiTestCase() { private val sensitiveNotificationProtectionController: SensitiveNotificationProtectionController = mock() - private val stackController: NotifStackController = mock() private val section: NotifSection = mock() private val row: ExpandableNotificationRow = mock() @@ -87,25 +84,23 @@ class StackCoordinatorTest : SysuiTestCase() { @Test fun testSetRenderedListOnInteractor() { - afterRenderListListener.onAfterRenderList(listOf(entry), stackController) + afterRenderListListener.onAfterRenderList(listOf(entry)) verify(renderListInteractor).setRenderedList(eq(listOf(entry))) } @Test fun testSetNotificationStats_clearableAlerting() { whenever(section.bucket).thenReturn(BUCKET_ALERTING) - afterRenderListListener.onAfterRenderList(listOf(entry), stackController) + afterRenderListListener.onAfterRenderList(listOf(entry)) verify(activeNotificationsInteractor) .setNotifStats( NotifStats( - 1, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = true, hasNonClearableSilentNotifs = false, hasClearableSilentNotifs = false, ) ) - verifyNoMoreInteractions(stackController) } @Test @@ -113,35 +108,31 @@ class StackCoordinatorTest : SysuiTestCase() { fun testSetNotificationStats_isSensitiveStateActive_nonClearableAlerting() { whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) whenever(section.bucket).thenReturn(BUCKET_ALERTING) - afterRenderListListener.onAfterRenderList(listOf(entry), stackController) + afterRenderListListener.onAfterRenderList(listOf(entry)) verify(activeNotificationsInteractor) .setNotifStats( NotifStats( - 1, hasNonClearableAlertingNotifs = true, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = false, hasClearableSilentNotifs = false, ) ) - verifyNoMoreInteractions(stackController) } @Test fun testSetNotificationStats_clearableSilent() { whenever(section.bucket).thenReturn(BUCKET_SILENT) - afterRenderListListener.onAfterRenderList(listOf(entry), stackController) + afterRenderListListener.onAfterRenderList(listOf(entry)) verify(activeNotificationsInteractor) .setNotifStats( NotifStats( - 1, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = false, hasClearableSilentNotifs = true, ) ) - verifyNoMoreInteractions(stackController) } @Test @@ -149,35 +140,31 @@ class StackCoordinatorTest : SysuiTestCase() { fun testSetNotificationStats_isSensitiveStateActive_nonClearableSilent() { whenever(sensitiveNotificationProtectionController.isSensitiveStateActive).thenReturn(true) whenever(section.bucket).thenReturn(BUCKET_SILENT) - afterRenderListListener.onAfterRenderList(listOf(entry), stackController) + afterRenderListListener.onAfterRenderList(listOf(entry)) verify(activeNotificationsInteractor) .setNotifStats( NotifStats( - 1, hasNonClearableAlertingNotifs = false, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = true, hasClearableSilentNotifs = false, ) ) - verifyNoMoreInteractions(stackController) } @Test fun testSetNotificationStats_nonClearableRedacted() { entry.setSensitive(true, true) whenever(section.bucket).thenReturn(BUCKET_ALERTING) - afterRenderListListener.onAfterRenderList(listOf(entry), stackController) + afterRenderListListener.onAfterRenderList(listOf(entry)) verify(activeNotificationsInteractor) .setNotifStats( NotifStats( - 1, hasNonClearableAlertingNotifs = true, hasClearableAlertingNotifs = false, hasNonClearableSilentNotifs = false, hasClearableSilentNotifs = false, ) ) - verifyNoMoreInteractions(stackController) } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index bd2714211796..3f6484f0f58e 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -8571,6 +8571,12 @@ public class AudioService extends IAudioService.Stub return true; } + private boolean shouldPreserveVolume(boolean userSwitch, VolumeGroupState vgs) { + // as for STREAM_MUSIC, preserve volume from one user to the next except + // Android Automotive platform + return (userSwitch && vgs.isMusic()) && !isPlatformAutomotive(); + } + private void readVolumeGroupsSettings(boolean userSwitch) { synchronized (mSettingsLock) { synchronized (VolumeStreamState.class) { @@ -8579,8 +8585,7 @@ public class AudioService extends IAudioService.Stub } for (int i = 0; i < sVolumeGroupStates.size(); i++) { VolumeGroupState vgs = sVolumeGroupStates.valueAt(i); - // as for STREAM_MUSIC, preserve volume from one user to the next. - if (!(userSwitch && vgs.isMusic())) { + if (!shouldPreserveVolume(userSwitch, vgs)) { vgs.clearIndexCache(); vgs.readSettings(); } @@ -9019,6 +9024,11 @@ public class AudioService extends IAudioService.Stub mIndexMap.clear(); } + private @UserIdInt int getVolumePersistenceUserId() { + return isMusic() && !isPlatformAutomotive() + ? UserHandle.USER_SYSTEM : UserHandle.USER_CURRENT; + } + private void persistVolumeGroup(int device) { // No need to persist the index if the volume group is backed up // by a public stream type as this is redundant @@ -9036,7 +9046,7 @@ public class AudioService extends IAudioService.Stub boolean success = mSettings.putSystemIntForUser(mContentResolver, getSettingNameForDevice(device), getIndex(device), - isMusic() ? UserHandle.USER_SYSTEM : UserHandle.USER_CURRENT); + getVolumePersistenceUserId()); if (!success) { Log.e(TAG, "persistVolumeGroup failed for group " + mAudioVolumeGroup.name()); } @@ -9059,7 +9069,7 @@ public class AudioService extends IAudioService.Stub String name = getSettingNameForDevice(device); index = mSettings.getSystemIntForUser( mContentResolver, name, defaultIndex, - isMusic() ? UserHandle.USER_SYSTEM : UserHandle.USER_CURRENT); + getVolumePersistenceUserId()); if (index == -1) { continue; } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index c8192e534f5c..b530da2a5f5e 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -2246,10 +2246,6 @@ public final class DisplayManagerService extends SystemService { @GuardedBy("mSyncRoot") private void handleLogicalDisplayDisconnectedLocked(LogicalDisplay display) { - if (!mFlags.isConnectedDisplayManagementEnabled()) { - Slog.e(TAG, "DisplayDisconnected shouldn't be received when the flag is off"); - return; - } releaseDisplayAndEmitEvent(display, DisplayManagerGlobal.EVENT_DISPLAY_DISCONNECTED); mExternalDisplayPolicy.handleLogicalDisplayDisconnectedLocked(display); } @@ -2315,11 +2311,6 @@ public final class DisplayManagerService extends SystemService { @SuppressLint("AndroidFrameworkRequiresPermission") private void handleLogicalDisplayConnectedLocked(LogicalDisplay display) { - if (!mFlags.isConnectedDisplayManagementEnabled()) { - Slog.e(TAG, "DisplayConnected shouldn't be received when the flag is off"); - return; - } - setupLogicalDisplay(display); if (ExternalDisplayPolicy.isExternalDisplayLocked(display)) { @@ -2346,9 +2337,6 @@ public final class DisplayManagerService extends SystemService { private void handleLogicalDisplayAddedLocked(LogicalDisplay display) { final int displayId = display.getDisplayIdLocked(); final boolean isDefault = displayId == Display.DEFAULT_DISPLAY; - if (!mFlags.isConnectedDisplayManagementEnabled()) { - setupLogicalDisplay(display); - } // Wake up waitForDefaultDisplay. if (isDefault) { @@ -2443,21 +2431,17 @@ public final class DisplayManagerService extends SystemService { } private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) { - // With display management, the display is removed when disabled, and it might still exist. + // The display is removed when disabled, and it might still exist. // Resources must only be released when the disconnected signal is received. - if (mFlags.isConnectedDisplayManagementEnabled()) { - if (display.isValidLocked()) { - updateViewportPowerStateLocked(display); - } + if (display.isValidLocked()) { + updateViewportPowerStateLocked(display); + } - // Note: This method is only called if the display was enabled before being removed. - sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); + // Note: This method is only called if the display was enabled before being removed. + sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); - if (display.isValidLocked()) { - applyDisplayChangedLocked(display); - } - } else { - releaseDisplayAndEmitEvent(display, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); + if (display.isValidLocked()) { + applyDisplayChangedLocked(display); } if (mDisplayTopologyCoordinator != null) { mDisplayTopologyCoordinator.onDisplayRemoved(display.getDisplayIdLocked()); @@ -4565,13 +4549,11 @@ public final class DisplayManagerService extends SystemService { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); - if (mFlags.isConnectedDisplayManagementEnabled()) { - if ((internalEventFlagsMask - & DisplayManagerGlobal - .INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { - mContext.enforceCallingOrSelfPermission(MANAGE_DISPLAYS, - "Permission required to get signals about connection events."); - } + if ((internalEventFlagsMask + & DisplayManagerGlobal + .INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) { + mContext.enforceCallingOrSelfPermission(MANAGE_DISPLAYS, + "Permission required to get signals about connection events."); } final long token = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java index e46397bc8ab7..f6b2591ea440 100644 --- a/services/core/java/com/android/server/display/DisplayManagerShellCommand.java +++ b/services/core/java/com/android/server/display/DisplayManagerShellCommand.java @@ -179,12 +179,10 @@ class DisplayManagerShellCommand extends ShellCommand { pw.println(" Sets brightness to docked + idle screen brightness mode"); pw.println(" undock"); pw.println(" Sets brightness to active (normal) screen brightness mode"); - if (mFlags.isConnectedDisplayManagementEnabled()) { - pw.println(" enable-display DISPLAY_ID"); - pw.println(" Enable the DISPLAY_ID. Only possible if this is a connected display."); - pw.println(" disable-display DISPLAY_ID"); - pw.println(" Disable the DISPLAY_ID. Only possible if this is a connected display."); - } + pw.println(" enable-display DISPLAY_ID"); + pw.println(" Enable the DISPLAY_ID. Only possible if this is a connected display."); + pw.println(" disable-display DISPLAY_ID"); + pw.println(" Disable the DISPLAY_ID. Only possible if this is a connected display."); pw.println(" power-reset DISPLAY_ID"); pw.println(" Turn the DISPLAY_ID power to a state the display supposed to have."); pw.println(" power-off DISPLAY_ID"); @@ -601,11 +599,6 @@ class DisplayManagerShellCommand extends ShellCommand { } private int setDisplayEnabled(boolean enable) { - if (!mFlags.isConnectedDisplayManagementEnabled()) { - getErrPrintWriter() - .println("Error: external display management is not available on this device."); - return 1; - } final String displayIdText = getNextArg(); if (displayIdText == null) { getErrPrintWriter().println("Error: no displayId specified"); diff --git a/services/core/java/com/android/server/display/ExternalDisplayPolicy.java b/services/core/java/com/android/server/display/ExternalDisplayPolicy.java index 519763a1c3db..a47853c8e555 100644 --- a/services/core/java/com/android/server/display/ExternalDisplayPolicy.java +++ b/services/core/java/com/android/server/display/ExternalDisplayPolicy.java @@ -142,14 +142,6 @@ class ExternalDisplayPolicy { mDisplayIdsWaitingForBootCompletion.clear(); } - if (!mFlags.isConnectedDisplayManagementEnabled()) { - if (DEBUG) { - Slog.d(TAG, "External display management is not enabled on your device:" - + " cannot register thermal listener."); - } - return; - } - if (!mFlags.isConnectedDisplayErrorHandlingEnabled()) { if (DEBUG) { Slog.d(TAG, "ConnectedDisplayErrorHandlingEnabled is not enabled on your device:" @@ -173,14 +165,6 @@ class ExternalDisplayPolicy { return; } - if (!mFlags.isConnectedDisplayManagementEnabled()) { - if (DEBUG) { - Slog.d(TAG, "setExternalDisplayEnabledLocked: External display management is not" - + " enabled on your device, cannot enable/disable display."); - } - return; - } - if (enabled && !isExternalDisplayAllowed()) { Slog.w(TAG, "setExternalDisplayEnabledLocked: External display can not be enabled" + " because it is currently not allowed."); @@ -202,14 +186,6 @@ class ExternalDisplayPolicy { return; } - if (!mFlags.isConnectedDisplayManagementEnabled()) { - if (DEBUG) { - Slog.d(TAG, "handleExternalDisplayConnectedLocked connected display management" - + " flag is off"); - } - return; - } - if (!mIsBootCompleted) { mDisplayIdsWaitingForBootCompletion.add(logicalDisplay.getDisplayIdLocked()); return; @@ -251,10 +227,6 @@ class ExternalDisplayPolicy { void handleLogicalDisplayDisconnectedLocked(@NonNull final LogicalDisplay logicalDisplay) { // Type of the display here is always UNKNOWN, so we can't verify it is an external display - if (!mFlags.isConnectedDisplayManagementEnabled()) { - return; - } - var displayId = logicalDisplay.getDisplayIdLocked(); if (mDisplayIdsWaitingForBootCompletion.remove(displayId)) { return; @@ -271,10 +243,6 @@ class ExternalDisplayPolicy { return; } - if (!mFlags.isConnectedDisplayManagementEnabled()) { - return; - } - mExternalDisplayStatsService.onDisplayAdded(logicalDisplay.getDisplayIdLocked()); } @@ -289,10 +257,6 @@ class ExternalDisplayPolicy { } } - if (!mFlags.isConnectedDisplayManagementEnabled()) { - return; - } - if (isShown) { mExternalDisplayStatsService.onPresentationWindowAdded(displayId); } else { @@ -306,12 +270,6 @@ class ExternalDisplayPolicy { return; } - if (!mFlags.isConnectedDisplayManagementEnabled()) { - Slog.e(TAG, "disableExternalDisplayLocked shouldn't be called when the" - + " connected display management flag is off"); - return; - } - if (!mFlags.isConnectedDisplayErrorHandlingEnabled()) { if (DEBUG) { Slog.d(TAG, "disableExternalDisplayLocked shouldn't be called when the" diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 006921572977..ecc8896b69c6 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -823,18 +823,13 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { if (wasPreviouslyUpdated) { // The display isn't actually removed from our internal data structures until // after the notification is sent; see {@link #sendUpdatesForDisplaysLocked}. - if (mFlags.isConnectedDisplayManagementEnabled()) { - if (mDisplaysEnabledCache.get(displayId)) { - // We still need to send LOGICAL_DISPLAY_EVENT_DISCONNECTED - reloop = true; - logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_REMOVED; - } else { - mUpdatedLogicalDisplays.delete(displayId); - logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_DISCONNECTED; - } + if (mDisplaysEnabledCache.get(displayId)) { + // We still need to send LOGICAL_DISPLAY_EVENT_DISCONNECTED + reloop = true; + logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_REMOVED; } else { mUpdatedLogicalDisplays.delete(displayId); - logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_REMOVED; + logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_DISCONNECTED; } } else { // This display never left this class, safe to remove without notification @@ -845,20 +840,15 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { // The display is new. } else if (!wasPreviouslyUpdated) { - if (mFlags.isConnectedDisplayManagementEnabled()) { - // We still need to send LOGICAL_DISPLAY_EVENT_ADDED - reloop = true; - logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CONNECTED; - } else { - logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_ADDED; - } + // We still need to send LOGICAL_DISPLAY_EVENT_ADDED + reloop = true; + logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_CONNECTED; // Underlying displays device has changed to a different one. } else if (!TextUtils.equals(mTempDisplayInfo.uniqueId, newDisplayInfo.uniqueId)) { logicalDisplayEventMask |= LOGICAL_DISPLAY_EVENT_SWAPPED; // Something about the display device has changed. - } else if (mFlags.isConnectedDisplayManagementEnabled() - && wasPreviouslyEnabled != isCurrentlyEnabled) { + } else if (wasPreviouslyEnabled != isCurrentlyEnabled) { int event = isCurrentlyEnabled ? LOGICAL_DISPLAY_EVENT_ADDED : LOGICAL_DISPLAY_EVENT_REMOVED; logicalDisplayEventMask |= event; @@ -936,17 +926,13 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION); sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_ADDED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REMOVED); - if (mFlags.isConnectedDisplayManagementEnabled()) { - sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DISCONNECTED); - } + sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DISCONNECTED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_BASIC_CHANGED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REFRESH_RATE_CHANGED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_STATE_CHANGED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED); - if (mFlags.isConnectedDisplayManagementEnabled()) { - sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CONNECTED); - } + sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CONNECTED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED); sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_HDR_SDR_RATIO_CHANGED); sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_CHANGED); @@ -996,23 +982,15 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { + "display=" + id + " with device=" + uniqueId); } - if (mFlags.isConnectedDisplayManagementEnabled()) { - if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_ADDED) { - mDisplaysEnabledCache.put(id, true); - } else if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_REMOVED) { - mDisplaysEnabledCache.delete(id); - } + if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_ADDED) { + mDisplaysEnabledCache.put(id, true); + } else if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_REMOVED) { + mDisplaysEnabledCache.delete(id); } mListener.onLogicalDisplayEventLocked(display, logicalDisplayEvent); - if (mFlags.isConnectedDisplayManagementEnabled()) { - if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_DISCONNECTED) { - mLogicalDisplays.delete(id); - } - } else if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_REMOVED) { - // We wait until we sent the EVENT_REMOVED event before actually removing the - // display. + if (logicalDisplayEvent == LOGICAL_DISPLAY_EVENT_DISCONNECTED) { mLogicalDisplays.delete(id); } } diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java index addfbf1833b9..4e57d6791ff6 100644 --- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java +++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java @@ -42,10 +42,6 @@ public class DisplayManagerFlags { Flags.FLAG_ENABLE_PORT_IN_DISPLAY_LAYOUT, Flags::enablePortInDisplayLayout); - private final FlagState mConnectedDisplayManagementFlagState = new FlagState( - Flags.FLAG_ENABLE_CONNECTED_DISPLAY_MANAGEMENT, - Flags::enableConnectedDisplayManagement); - private final FlagState mAdaptiveToneImprovements1 = new FlagState( Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1, Flags::enableAdaptiveToneImprovements1); @@ -269,11 +265,6 @@ public class DisplayManagerFlags { return mPortInDisplayLayoutFlagState.isEnabled(); } - /** Returns whether connected display management is enabled or not. */ - public boolean isConnectedDisplayManagementEnabled() { - return mConnectedDisplayManagementFlagState.isEnabled(); - } - /** Returns whether power throttling clamper is enabled on not. */ public boolean isPowerThrottlingClamperEnabled() { return mPowerThrottlingClamperFlagState.isEnabled(); @@ -572,7 +563,6 @@ public class DisplayManagerFlags { pw.println(" " + mAdaptiveToneImprovements2); pw.println(" " + mBackUpSmoothDisplayAndForcePeakRefreshRateFlagState); pw.println(" " + mConnectedDisplayErrorHandlingFlagState); - pw.println(" " + mConnectedDisplayManagementFlagState); pw.println(" " + mDisplayOffloadFlagState); pw.println(" " + mExternalDisplayLimitModeState); pw.println(" " + mDisplayTopology); 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 eccbbb14c4ea..afae07c88f8d 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 @@ -29,14 +29,6 @@ flag { } flag { - name: "enable_connected_display_management" - namespace: "display_manager" - description: "Feature flag for Connected Display management" - bug: "280739508" - is_fixed_read_only: true -} - -flag { name: "enable_power_throttling_clamper" namespace: "display_manager" description: "Feature flag for Power Throttling Clamper" diff --git a/services/core/java/com/android/server/flags/services.aconfig b/services/core/java/com/android/server/flags/services.aconfig index eea5c982c537..4505d0e2d799 100644 --- a/services/core/java/com/android/server/flags/services.aconfig +++ b/services/core/java/com/android/server/flags/services.aconfig @@ -78,3 +78,11 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "datetime_notifications" + # "location" is used by the Android System Time team for feature flags. + namespace: "location" + description: "Enable the time notifications feature, a toggle to enable/disable time-related notifications in Date & Time Settings" + bug: "283267917" +} diff --git a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java index 17d7a14d9129..e1b76222072e 100644 --- a/services/core/java/com/android/server/pm/SharedLibrariesImpl.java +++ b/services/core/java/com/android/server/pm/SharedLibrariesImpl.java @@ -612,7 +612,7 @@ public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable final PackageSetting staticLibPkgSetting = mPm.getPackageSettingForMutation(sharedLibraryInfo.getPackageName()); if (staticLibPkgSetting == null) { - Slog.wtf(TAG, "Shared lib without setting: " + sharedLibraryInfo); + Slog.w(TAG, "Shared lib without setting: " + sharedLibraryInfo); continue; } for (int u = 0; u < installedUserCount; u++) { diff --git a/services/core/java/com/android/server/timedetector/ServerFlags.java b/services/core/java/com/android/server/timedetector/ServerFlags.java index 2049a0288f5a..b651c7ba34c3 100644 --- a/services/core/java/com/android/server/timedetector/ServerFlags.java +++ b/services/core/java/com/android/server/timedetector/ServerFlags.java @@ -72,8 +72,12 @@ public final class ServerFlags { KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT, KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED, KEY_ENHANCED_METRICS_COLLECTION_ENABLED, + KEY_TIME_ZONE_NOTIFICATIONS_SUPPORTED, + KEY_TIME_ZONE_NOTIFICATIONS_ENABLED_DEFAULT, + KEY_TIME_ZONE_NOTIFICATIONS_TRACKING_SUPPORTED, + KEY_TIME_ZONE_MANUAL_CHANGE_TRACKING_SUPPORTED }) - @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER }) + @Target({ElementType.TYPE_USE, ElementType.TYPE_PARAMETER}) @Retention(RetentionPolicy.SOURCE) @interface DeviceConfigKey {} @@ -192,6 +196,31 @@ public final class ServerFlags { "enhanced_metrics_collection_enabled"; /** + * The key to control support for time zone notifications under certain circumstances. + */ + public static final @DeviceConfigKey String KEY_TIME_ZONE_NOTIFICATIONS_SUPPORTED = + "time_zone_notifications_supported"; + + /** + * The key for the default value used to determine whether time zone notifications is enabled + * when the user hasn't explicitly set it yet. + */ + public static final @DeviceConfigKey String KEY_TIME_ZONE_NOTIFICATIONS_ENABLED_DEFAULT = + "time_zone_notifications_enabled_default"; + + /** + * The key to control support for time zone notifications tracking under certain circumstances. + */ + public static final @DeviceConfigKey String KEY_TIME_ZONE_NOTIFICATIONS_TRACKING_SUPPORTED = + "time_zone_notifications_tracking_supported"; + + /** + * The key to control support for time zone manual change tracking under certain circumstances. + */ + public static final @DeviceConfigKey String KEY_TIME_ZONE_MANUAL_CHANGE_TRACKING_SUPPORTED = + "time_zone_manual_change_tracking_supported"; + + /** * The registered listeners and the keys to trigger on. The value is explicitly a HashSet to * ensure O(1) lookup performance when working out whether a listener should trigger. */ diff --git a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java index 3579246b660f..0495f54cb154 100644 --- a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java +++ b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java @@ -286,7 +286,8 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { // This check is racey, but the whole settings update process is racey. This check prevents // a ConfigurationChangeListener callback triggering due to ContentObserver's still // triggering *sometimes* for no-op updates. Because callbacks are async this is necessary - // for stable behavior during tests. + // for stable behavior during tests. This behavior is copied from + // setAutoDetectionEnabledIfRequired and assumed to be the correct way. if (getAutoDetectionEnabledSetting() != enabled) { Settings.Global.putInt(mCr, Settings.Global.AUTO_TIME, enabled ? 1 : 0); } diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java index fc659c5cb627..c4c86a429dd6 100644 --- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java +++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java @@ -65,6 +65,10 @@ public final class ConfigurationInternal { private final boolean mUserConfigAllowed; private final boolean mLocationEnabledSetting; private final boolean mGeoDetectionEnabledSetting; + private final boolean mNotificationsSupported; + private final boolean mNotificationsEnabledSetting; + private final boolean mNotificationTrackingSupported; + private final boolean mManualChangeTrackingSupported; private ConfigurationInternal(Builder builder) { mTelephonyDetectionSupported = builder.mTelephonyDetectionSupported; @@ -78,6 +82,10 @@ public final class ConfigurationInternal { mUserConfigAllowed = builder.mUserConfigAllowed; mLocationEnabledSetting = builder.mLocationEnabledSetting; mGeoDetectionEnabledSetting = builder.mGeoDetectionEnabledSetting; + mNotificationsSupported = builder.mNotificationsSupported; + mNotificationsEnabledSetting = builder.mNotificationsEnabledSetting; + mNotificationTrackingSupported = builder.mNotificationsTrackingSupported; + mManualChangeTrackingSupported = builder.mManualChangeTrackingSupported; } /** Returns true if the device supports any form of auto time zone detection. */ @@ -104,6 +112,27 @@ public final class ConfigurationInternal { } /** + * Returns true if the device supports time-related notifications. + */ + public boolean areNotificationsSupported() { + return mNotificationsSupported; + } + + /** + * Returns true if the device supports tracking of time-related notifications. + */ + public boolean isNotificationTrackingSupported() { + return areNotificationsSupported() && mNotificationTrackingSupported; + } + + /** + * Returns true if the device supports tracking of time zone manual changes. + */ + public boolean isManualChangeTrackingSupported() { + return mManualChangeTrackingSupported; + } + + /** * Returns {@code true} if location time zone detection should run when auto time zone detection * is enabled on supported devices, even when the user has not enabled the algorithm explicitly * in settings. Enabled for internal testing only. See {@link #isGeoDetectionExecutionEnabled()} @@ -223,6 +252,15 @@ public final class ConfigurationInternal { && getGeoDetectionRunInBackgroundEnabledSetting(); } + /** Returns true if time-related notifications can be shown on this device. */ + public boolean getNotificationsEnabledBehavior() { + return areNotificationsSupported() && getNotificationsEnabledSetting(); + } + + private boolean getNotificationsEnabledSetting() { + return mNotificationsEnabledSetting; + } + @NonNull public TimeZoneCapabilities asCapabilities(boolean bypassUserPolicyChecks) { UserHandle userHandle = UserHandle.of(mUserId); @@ -283,6 +321,14 @@ public final class ConfigurationInternal { } builder.setSetManualTimeZoneCapability(suggestManualTimeZoneCapability); + final @CapabilityState int configureNotificationsEnabledCapability; + if (areNotificationsSupported()) { + configureNotificationsEnabledCapability = CAPABILITY_POSSESSED; + } else { + configureNotificationsEnabledCapability = CAPABILITY_NOT_SUPPORTED; + } + builder.setConfigureNotificationsEnabledCapability(configureNotificationsEnabledCapability); + return builder.build(); } @@ -291,6 +337,7 @@ public final class ConfigurationInternal { return new TimeZoneConfiguration.Builder() .setAutoDetectionEnabled(getAutoDetectionEnabledSetting()) .setGeoDetectionEnabled(getGeoDetectionEnabledSetting()) + .setNotificationsEnabled(getNotificationsEnabledSetting()) .build(); } @@ -307,6 +354,9 @@ public final class ConfigurationInternal { if (newConfiguration.hasIsGeoDetectionEnabled()) { builder.setGeoDetectionEnabledSetting(newConfiguration.isGeoDetectionEnabled()); } + if (newConfiguration.hasIsNotificationsEnabled()) { + builder.setNotificationsEnabledSetting(newConfiguration.areNotificationsEnabled()); + } return builder.build(); } @@ -328,7 +378,11 @@ public final class ConfigurationInternal { && mEnhancedMetricsCollectionEnabled == that.mEnhancedMetricsCollectionEnabled && mAutoDetectionEnabledSetting == that.mAutoDetectionEnabledSetting && mLocationEnabledSetting == that.mLocationEnabledSetting - && mGeoDetectionEnabledSetting == that.mGeoDetectionEnabledSetting; + && mGeoDetectionEnabledSetting == that.mGeoDetectionEnabledSetting + && mNotificationsSupported == that.mNotificationsSupported + && mNotificationsEnabledSetting == that.mNotificationsEnabledSetting + && mNotificationTrackingSupported == that.mNotificationTrackingSupported + && mManualChangeTrackingSupported == that.mManualChangeTrackingSupported; } @Override @@ -336,7 +390,9 @@ public final class ConfigurationInternal { return Objects.hash(mUserId, mUserConfigAllowed, mTelephonyDetectionSupported, mGeoDetectionSupported, mTelephonyFallbackSupported, mGeoDetectionRunInBackgroundEnabled, mEnhancedMetricsCollectionEnabled, - mAutoDetectionEnabledSetting, mLocationEnabledSetting, mGeoDetectionEnabledSetting); + mAutoDetectionEnabledSetting, mLocationEnabledSetting, mGeoDetectionEnabledSetting, + mNotificationsSupported, mNotificationsEnabledSetting, + mNotificationTrackingSupported, mManualChangeTrackingSupported); } @Override @@ -352,6 +408,10 @@ public final class ConfigurationInternal { + ", mAutoDetectionEnabledSetting=" + mAutoDetectionEnabledSetting + ", mLocationEnabledSetting=" + mLocationEnabledSetting + ", mGeoDetectionEnabledSetting=" + mGeoDetectionEnabledSetting + + ", mNotificationsSupported=" + mNotificationsSupported + + ", mNotificationsEnabledSetting=" + mNotificationsEnabledSetting + + ", mNotificationTrackingSupported=" + mNotificationTrackingSupported + + ", mManualChangeTrackingSupported=" + mManualChangeTrackingSupported + '}'; } @@ -370,6 +430,10 @@ public final class ConfigurationInternal { private boolean mAutoDetectionEnabledSetting; private boolean mLocationEnabledSetting; private boolean mGeoDetectionEnabledSetting; + private boolean mNotificationsSupported; + private boolean mNotificationsEnabledSetting; + private boolean mNotificationsTrackingSupported; + private boolean mManualChangeTrackingSupported; /** * Creates a new Builder. @@ -390,6 +454,10 @@ public final class ConfigurationInternal { this.mAutoDetectionEnabledSetting = toCopy.mAutoDetectionEnabledSetting; this.mLocationEnabledSetting = toCopy.mLocationEnabledSetting; this.mGeoDetectionEnabledSetting = toCopy.mGeoDetectionEnabledSetting; + this.mNotificationsSupported = toCopy.mNotificationsSupported; + this.mNotificationsEnabledSetting = toCopy.mNotificationsEnabledSetting; + this.mNotificationsTrackingSupported = toCopy.mNotificationTrackingSupported; + this.mManualChangeTrackingSupported = toCopy.mManualChangeTrackingSupported; } /** @@ -475,6 +543,38 @@ public final class ConfigurationInternal { return this; } + /** + * Sets the value of the time notification setting for this user. + */ + public Builder setNotificationsEnabledSetting(boolean enabled) { + mNotificationsEnabledSetting = enabled; + return this; + } + + /** + * Sets whether time zone notifications are supported on this device. + */ + public Builder setNotificationsSupported(boolean enabled) { + mNotificationsSupported = enabled; + return this; + } + + /** + * Sets whether time zone notification tracking is supported on this device. + */ + public Builder setNotificationsTrackingSupported(boolean supported) { + mNotificationsTrackingSupported = supported; + return this; + } + + /** + * Sets whether time zone manual change tracking are supported on this device. + */ + public Builder setManualChangeTrackingSupported(boolean supported) { + mManualChangeTrackingSupported = supported; + return this; + } + /** Returns a new {@link ConfigurationInternal}. */ @NonNull public ConfigurationInternal build() { diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java index f1248a3f5f0e..d809fc6b6eea 100644 --- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java +++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java @@ -68,7 +68,11 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_DEFAULT, ServerFlags.KEY_LOCATION_TIME_ZONE_DETECTION_SETTING_ENABLED_OVERRIDE, ServerFlags.KEY_TIME_ZONE_DETECTOR_AUTO_DETECTION_ENABLED_DEFAULT, - ServerFlags.KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED + ServerFlags.KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED, + ServerFlags.KEY_TIME_ZONE_NOTIFICATIONS_SUPPORTED, + ServerFlags.KEY_TIME_ZONE_NOTIFICATIONS_ENABLED_DEFAULT, + ServerFlags.KEY_TIME_ZONE_NOTIFICATIONS_TRACKING_SUPPORTED, + ServerFlags.KEY_TIME_ZONE_MANUAL_CHANGE_TRACKING_SUPPORTED ); /** @@ -100,11 +104,16 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { @Nullable private static ServiceConfigAccessor sInstance; - @NonNull private final Context mContext; - @NonNull private final ServerFlags mServerFlags; - @NonNull private final ContentResolver mCr; - @NonNull private final UserManager mUserManager; - @NonNull private final LocationManager mLocationManager; + @NonNull + private final Context mContext; + @NonNull + private final ServerFlags mServerFlags; + @NonNull + private final ContentResolver mCr; + @NonNull + private final UserManager mUserManager; + @NonNull + private final LocationManager mLocationManager; @GuardedBy("this") @NonNull @@ -193,6 +202,9 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { contentResolver.registerContentObserver( Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE_EXPLICIT), true, contentObserver); + contentResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.TIME_ZONE_NOTIFICATIONS), true, + contentObserver); // Add async callbacks for user scoped location settings being changed. contentResolver.registerContentObserver( @@ -331,6 +343,14 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { setGeoDetectionEnabledSettingIfRequired(userId, geoDetectionEnabledSetting); } } + + if (areNotificationsSupported()) { + if (requestedConfigurationUpdates.hasIsNotificationsEnabled()) { + setNotificationsEnabledSetting( + requestedConfigurationUpdates.areNotificationsEnabled()); + } + setNotificationsEnabledIfRequired(newConfiguration.areNotificationsEnabled()); + } } @Override @@ -348,6 +368,10 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { .setUserConfigAllowed(isUserConfigAllowed(userId)) .setLocationEnabledSetting(getLocationEnabledSetting(userId)) .setGeoDetectionEnabledSetting(getGeoDetectionEnabledSetting(userId)) + .setNotificationsSupported(areNotificationsSupported()) + .setNotificationsEnabledSetting(getNotificationsEnabledSetting()) + .setNotificationsTrackingSupported(isNotificationTrackingSupported()) + .setManualChangeTrackingSupported(isManualChangeTrackingSupported()) .build(); } @@ -421,6 +445,49 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { } } + private boolean areNotificationsSupported() { + return mServerFlags.getBoolean( + ServerFlags.KEY_TIME_ZONE_NOTIFICATIONS_SUPPORTED, + getConfigBoolean(R.bool.config_enableTimeZoneNotificationsSupported)); + } + + private boolean isNotificationTrackingSupported() { + return mServerFlags.getBoolean( + ServerFlags.KEY_TIME_ZONE_NOTIFICATIONS_TRACKING_SUPPORTED, + getConfigBoolean(R.bool.config_enableTimeZoneNotificationsTrackingSupported)); + } + + private boolean isManualChangeTrackingSupported() { + return mServerFlags.getBoolean( + ServerFlags.KEY_TIME_ZONE_MANUAL_CHANGE_TRACKING_SUPPORTED, + getConfigBoolean(R.bool.config_enableTimeZoneManualChangeTrackingSupported)); + } + + private boolean getNotificationsEnabledSetting() { + final boolean notificationsEnabledByDefault = areNotificationsEnabledByDefault(); + return Settings.Global.getInt(mCr, Settings.Global.TIME_ZONE_NOTIFICATIONS, + (notificationsEnabledByDefault ? 1 : 0) /* defaultValue */) != 0; + } + + private boolean areNotificationsEnabledByDefault() { + return mServerFlags.getBoolean( + ServerFlags.KEY_TIME_ZONE_NOTIFICATIONS_ENABLED_DEFAULT, true); + } + + private void setNotificationsEnabledSetting(boolean enabled) { + Settings.Global.putInt(mCr, Settings.Global.TIME_ZONE_NOTIFICATIONS, enabled ? 1 : 0); + } + + private void setNotificationsEnabledIfRequired(boolean enabled) { + // This check is racey, but the whole settings update process is racey. This check prevents + // a ConfigurationChangeListener callback triggering due to ContentObserver's still + // triggering *sometimes* for no-op updates. Because callbacks are async this is necessary + // for stable behavior during tests. + if (getNotificationsEnabledSetting() != enabled) { + Settings.Global.putInt(mCr, Settings.Global.TIME_ZONE_NOTIFICATIONS, enabled ? 1 : 0); + } + } + @Override public void addLocationTimeZoneManagerConfigListener( @NonNull StateChangeListener listener) { @@ -441,8 +508,7 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { @Override public boolean isGeoTimeZoneDetectionFeatureSupportedInConfig() { - return mContext.getResources().getBoolean( - com.android.internal.R.bool.config_enableGeolocationTimeZoneDetection); + return getConfigBoolean(R.bool.config_enableGeolocationTimeZoneDetection); } @Override @@ -660,8 +726,7 @@ public final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { private boolean isTelephonyFallbackSupported() { return mServerFlags.getBoolean( ServerFlags.KEY_TIME_ZONE_DETECTOR_TELEPHONY_FALLBACK_SUPPORTED, - getConfigBoolean( - com.android.internal.R.bool.config_supportTelephonyTimeZoneFallback)); + getConfigBoolean(R.bool.config_supportTelephonyTimeZoneFallback)); } private boolean getConfigBoolean(int providerEnabledConfigId) { diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneChangeListener.java b/services/core/java/com/android/server/timezonedetector/TimeZoneChangeListener.java new file mode 100644 index 000000000000..e14326cc2d53 --- /dev/null +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneChangeListener.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.timezonedetector; + +import android.annotation.CurrentTimeMillisLong; +import android.annotation.ElapsedRealtimeLong; +import android.annotation.NonNull; +import android.annotation.UserIdInt; +import android.util.IndentingPrintWriter; + +import com.android.server.SystemTimeZone.TimeZoneConfidence; +import com.android.server.timezonedetector.TimeZoneDetectorStrategy.Origin; + +import java.util.Objects; + +public interface TimeZoneChangeListener { + + /** Record a time zone change. */ + void process(TimeZoneChangeEvent event); + + /** Dump internal state. */ + void dump(IndentingPrintWriter ipw); + + class TimeZoneChangeEvent { + + private final @ElapsedRealtimeLong long mElapsedRealtimeMillis; + private final @CurrentTimeMillisLong long mUnixEpochTimeMillis; + private final @Origin int mOrigin; + private final @UserIdInt int mUserId; + private final String mOldZoneId; + private final String mNewZoneId; + private final @TimeZoneConfidence int mNewConfidence; + private final String mCause; + + public TimeZoneChangeEvent(@ElapsedRealtimeLong long elapsedRealtimeMillis, + @CurrentTimeMillisLong long unixEpochTimeMillis, + @Origin int origin, @UserIdInt int userId, @NonNull String oldZoneId, + @NonNull String newZoneId, int newConfidence, @NonNull String cause) { + mElapsedRealtimeMillis = elapsedRealtimeMillis; + mUnixEpochTimeMillis = unixEpochTimeMillis; + mOrigin = origin; + mUserId = userId; + mOldZoneId = Objects.requireNonNull(oldZoneId); + mNewZoneId = Objects.requireNonNull(newZoneId); + mNewConfidence = newConfidence; + mCause = Objects.requireNonNull(cause); + } + + public @ElapsedRealtimeLong long getElapsedRealtimeMillis() { + return mElapsedRealtimeMillis; + } + + public @CurrentTimeMillisLong long getUnixEpochTimeMillis() { + return mUnixEpochTimeMillis; + } + + public @Origin int getOrigin() { + return mOrigin; + } + + /** + * The ID of the user that triggered the change. + * + * <p>If automatic time zone is turned on, the user ID returned is the system's user id. + */ + public @UserIdInt int getUserId() { + return mUserId; + } + + public String getOldZoneId() { + return mOldZoneId; + } + + public String getNewZoneId() { + return mNewZoneId; + } + + @Override + public String toString() { + return "TimeZoneChangeEvent{" + + "mElapsedRealtimeMillis=" + mElapsedRealtimeMillis + + ", mUnixEpochTimeMillis=" + mUnixEpochTimeMillis + + ", mOrigin=" + mOrigin + + ", mUserId=" + mUserId + + ", mOldZoneId='" + mOldZoneId + '\'' + + ", mNewZoneId='" + mNewZoneId + '\'' + + ", mNewConfidence=" + mNewConfidence + + ", mCause='" + mCause + '\'' + + '}'; + } + } +} diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java index d914544566ff..af02ad88ad6a 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java @@ -18,6 +18,7 @@ package com.android.server.timezonedetector; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.time.ITimeZoneDetectorListener; import android.app.time.TimeZoneCapabilitiesAndConfig; @@ -73,6 +74,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub } @Override + @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public void onStart() { // Obtain / create the shared dependencies. Context context = getContext(); @@ -81,7 +83,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub ServiceConfigAccessor serviceConfigAccessor = ServiceConfigAccessorImpl.getInstance(context); TimeZoneDetectorStrategy timeZoneDetectorStrategy = - TimeZoneDetectorStrategyImpl.create(handler, serviceConfigAccessor); + TimeZoneDetectorStrategyImpl.create(context, handler, serviceConfigAccessor); DeviceActivityMonitor deviceActivityMonitor = DeviceActivityMonitorImpl.create(context, handler); diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java index 37e67c921634..8cfbe9daa970 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java @@ -15,6 +15,7 @@ */ package com.android.server.timezonedetector; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.time.TimeZoneCapabilitiesAndConfig; @@ -24,6 +25,11 @@ import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.util.IndentingPrintWriter; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + /** * The interface for the class that is responsible for setting the time zone on a device, used by * {@link TimeZoneDetectorService} and {@link TimeZoneDetectorInternal}. @@ -97,6 +103,22 @@ import android.util.IndentingPrintWriter; * @hide */ public interface TimeZoneDetectorStrategy extends Dumpable { + @IntDef({ ORIGIN_UNKNOWN, ORIGIN_MANUAL, ORIGIN_TELEPHONY, ORIGIN_LOCATION }) + @Retention(RetentionPolicy.SOURCE) + @Target({ ElementType.TYPE_USE, ElementType.TYPE_PARAMETER }) + @interface Origin {} + + /** Used when the origin of the time zone value cannot be inferred. */ + @Origin int ORIGIN_UNKNOWN = 0; + + /** Used when a time zone value originated from a user / manual settings. */ + @Origin int ORIGIN_MANUAL = 1; + + /** Used when a time zone value originated from a telephony signal. */ + @Origin int ORIGIN_TELEPHONY = 2; + + /** Used when a time zone value originated from a location signal. */ + @Origin int ORIGIN_LOCATION = 3; /** * Adds a listener that will be triggered when something changes that could affect the result diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java index dddb46f80724..19a28ddcdaeb 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java @@ -28,6 +28,7 @@ import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_LOW; import android.annotation.ElapsedRealtimeLong; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.UserIdInt; import android.app.time.DetectorStatusTypes; import android.app.time.LocationTimeZoneAlgorithmStatus; @@ -39,8 +40,10 @@ import android.app.time.TimeZoneDetectorStatus; import android.app.time.TimeZoneState; import android.app.timezonedetector.ManualTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion; +import android.content.Context; import android.os.Handler; import android.os.TimestampedValue; +import android.os.UserHandle; import android.util.IndentingPrintWriter; import android.util.Slog; @@ -72,12 +75,14 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat /** * Returns the device's currently configured time zone. May return an empty string. */ - @NonNull String getDeviceTimeZone(); + @NonNull + String getDeviceTimeZone(); /** * Returns the confidence of the device's current time zone. */ - @TimeZoneConfidence int getDeviceTimeZoneConfidence(); + @TimeZoneConfidence + int getDeviceTimeZoneConfidence(); /** * Sets the device's time zone, associated confidence, and records a debug log entry. @@ -115,7 +120,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat /** * The abstract score for an empty or invalid telephony suggestion. * - * Used to score telephony suggestions where there is no zone. + * <p>Used to score telephony suggestions where there is no zone. */ @VisibleForTesting public static final int TELEPHONY_SCORE_NONE = 0; @@ -123,11 +128,11 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat /** * The abstract score for a low quality telephony suggestion. * - * Used to score suggestions where: - * The suggested zone ID is one of several possibilities, and the possibilities have different - * offsets. + * <p>Used to score suggestions where: + * The suggested zone ID is one of several possibilities, + * and the possibilities have different offsets. * - * You would have to be quite desperate to want to use this choice. + * <p>You would have to be quite desperate to want to use this choice. */ @VisibleForTesting public static final int TELEPHONY_SCORE_LOW = 1; @@ -135,7 +140,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat /** * The abstract score for a medium quality telephony suggestion. * - * Used for: + * <p>Used for: * The suggested zone ID is one of several possibilities but at least the possibilities have the * same offset. Users would get the correct time but for the wrong reason. i.e. their device may * switch to DST at the wrong time and (for example) their calendar events. @@ -146,7 +151,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat /** * The abstract score for a high quality telephony suggestion. * - * Used for: + * <p>Used for: * The suggestion was for one zone ID and the answer was unambiguous and likely correct given * the info available. */ @@ -156,7 +161,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat /** * The abstract score for a highest quality telephony suggestion. * - * Used for: + * <p>Used for: * Suggestions that must "win" because they constitute test or emulator zone ID. */ @VisibleForTesting @@ -206,7 +211,8 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat private final ServiceConfigAccessor mServiceConfigAccessor; @GuardedBy("this") - @NonNull private final List<StateChangeListener> mStateChangeListeners = new ArrayList<>(); + @NonNull + private final List<StateChangeListener> mStateChangeListeners = new ArrayList<>(); /** * A snapshot of the current detector status. A local copy is cached because it is relatively @@ -244,8 +250,10 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat /** * Creates a new instance of {@link TimeZoneDetectorStrategyImpl}. */ + @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public static TimeZoneDetectorStrategyImpl create( - @NonNull Handler handler, @NonNull ServiceConfigAccessor serviceConfigAccessor) { + @NonNull Context context, @NonNull Handler handler, + @NonNull ServiceConfigAccessor serviceConfigAccessor) { Environment environment = new EnvironmentImpl(handler); return new TimeZoneDetectorStrategyImpl(serviceConfigAccessor, environment); @@ -468,7 +476,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat // later disables automatic time zone detection. mLatestManualSuggestion.set(suggestion); - setDeviceTimeZoneIfRequired(timeZoneId, cause); + setDeviceTimeZoneIfRequired(timeZoneId, ORIGIN_MANUAL, userId, cause); return true; } @@ -685,7 +693,7 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat // GeolocationTimeZoneSuggestion has no measure of quality. We assume all suggestions are // reliable. - String zoneId; + String timeZoneId; // Introduce bias towards the device's current zone when there are multiple zone suggested. String deviceTimeZone = mEnvironment.getDeviceTimeZone(); @@ -694,11 +702,12 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat Slog.d(LOG_TAG, "Geo tz suggestion contains current device time zone. Applying bias."); } - zoneId = deviceTimeZone; + timeZoneId = deviceTimeZone; } else { - zoneId = zoneIds.get(0); + timeZoneId = zoneIds.get(0); } - setDeviceTimeZoneIfRequired(zoneId, detectionReason); + setDeviceTimeZoneIfRequired(timeZoneId, ORIGIN_LOCATION, UserHandle.USER_SYSTEM, + detectionReason); return true; } @@ -779,8 +788,8 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat // Paranoia: Every suggestion above the SCORE_USAGE_THRESHOLD should have a non-null time // zone ID. - String zoneId = bestTelephonySuggestion.suggestion.getZoneId(); - if (zoneId == null) { + String timeZoneId = bestTelephonySuggestion.suggestion.getZoneId(); + if (timeZoneId == null) { Slog.w(LOG_TAG, "Empty zone suggestion scored higher than expected. This is an error:" + " bestTelephonySuggestion=" + bestTelephonySuggestion + ", detectionReason=" + detectionReason); @@ -790,11 +799,12 @@ public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrat String cause = "Found good suggestion:" + " bestTelephonySuggestion=" + bestTelephonySuggestion + ", detectionReason=" + detectionReason; - setDeviceTimeZoneIfRequired(zoneId, cause); + setDeviceTimeZoneIfRequired(timeZoneId, ORIGIN_TELEPHONY, UserHandle.USER_SYSTEM, cause); } @GuardedBy("this") - private void setDeviceTimeZoneIfRequired(@NonNull String newZoneId, @NonNull String cause) { + private void setDeviceTimeZoneIfRequired(@NonNull String newZoneId, @Origin int origin, + @UserIdInt int userId, @NonNull String cause) { String currentZoneId = mEnvironment.getDeviceTimeZone(); // All manual and automatic suggestions are considered high confidence as low-quality // suggestions are not currently passed on. diff --git a/services/core/java/com/android/server/vibrator/BasicToPwleSegmentAdapter.java b/services/core/java/com/android/server/vibrator/BasicToPwleSegmentAdapter.java index 54ae047a2858..0b676ff7d590 100644 --- a/services/core/java/com/android/server/vibrator/BasicToPwleSegmentAdapter.java +++ b/services/core/java/com/android/server/vibrator/BasicToPwleSegmentAdapter.java @@ -100,6 +100,11 @@ final class BasicToPwleSegmentAdapter implements VibrationSegmentsAdapter { } VibratorInfo.FrequencyProfile frequencyProfile = info.getFrequencyProfile(); + if (frequencyProfile.isEmpty()) { + // The frequency profile has an invalid frequency range, so keep the segments unchanged. + return repeatIndex; + } + float[] frequenciesHz = frequencyProfile.getFrequenciesHz(); float[] accelerationsGs = frequencyProfile.getOutputAccelerationsGs(); diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 89c7a3d89a54..6f308aa9b706 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -1631,7 +1631,7 @@ class ActivityMetricsLogger { int positionToLog = APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__NOT_LETTERBOXED_POSITION; if (isAppCompateStateChangedToLetterboxed(state)) { - positionToLog = activity.mAppCompatController.getAppCompatReachabilityOverrides() + positionToLog = activity.mAppCompatController.getReachabilityOverrides() .getLetterboxPositionForLogging(); } FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPAT_STATE_CHANGED, diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 29f1f93a844f..3e6315635571 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -8744,7 +8744,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A navBarInsets = Insets.NONE; } final AppCompatReachabilityOverrides reachabilityOverrides = - mAppCompatController.getAppCompatReachabilityOverrides(); + mAppCompatController.getReachabilityOverrides(); // Horizontal position int offsetX = 0; if (parentBounds.width() != screenResolvedBoundsWidth) { diff --git a/services/core/java/com/android/server/wm/AppCompatController.java b/services/core/java/com/android/server/wm/AppCompatController.java index 0967078deac3..c748264a833e 100644 --- a/services/core/java/com/android/server/wm/AppCompatController.java +++ b/services/core/java/com/android/server/wm/AppCompatController.java @@ -33,7 +33,7 @@ class AppCompatController { @NonNull private final AppCompatAspectRatioPolicy mAppCompatAspectRatioPolicy; @NonNull - private final AppCompatReachabilityPolicy mAppCompatReachabilityPolicy; + private final AppCompatReachabilityPolicy mReachabilityPolicy; @NonNull private final DesktopAppCompatAspectRatioPolicy mDesktopAppCompatAspectRatioPolicy; @NonNull @@ -58,7 +58,7 @@ class AppCompatController { mOrientationPolicy = new AppCompatOrientationPolicy(activityRecord, mAppCompatOverrides); mAppCompatAspectRatioPolicy = new AppCompatAspectRatioPolicy(activityRecord, mTransparentPolicy, mAppCompatOverrides); - mAppCompatReachabilityPolicy = new AppCompatReachabilityPolicy(activityRecord, + mReachabilityPolicy = new AppCompatReachabilityPolicy(activityRecord, wmService.mAppCompatConfiguration); mAppCompatLetterboxPolicy = new AppCompatLetterboxPolicy(activityRecord, wmService.mAppCompatConfiguration); @@ -109,8 +109,8 @@ class AppCompatController { } @NonNull - AppCompatReachabilityPolicy getAppCompatReachabilityPolicy() { - return mAppCompatReachabilityPolicy; + AppCompatReachabilityPolicy getReachabilityPolicy() { + return mReachabilityPolicy; } @NonNull @@ -124,8 +124,8 @@ class AppCompatController { } @NonNull - AppCompatReachabilityOverrides getAppCompatReachabilityOverrides() { - return mAppCompatOverrides.getAppCompatReachabilityOverrides(); + AppCompatReachabilityOverrides getReachabilityOverrides() { + return mAppCompatOverrides.getReachabilityOverrides(); } @NonNull diff --git a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java index e929fb414340..8866e39fecc9 100644 --- a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java @@ -205,7 +205,7 @@ class AppCompatLetterboxPolicy { } pw.println(prefix + " letterboxReason=" + AppCompatUtils.getLetterboxReasonString(mActivityRecord, mainWin)); - mActivityRecord.mAppCompatController.getAppCompatReachabilityPolicy().dump(pw, prefix); + mActivityRecord.mAppCompatController.getReachabilityPolicy().dump(pw, prefix); final AppCompatLetterboxOverrides letterboxOverride = mActivityRecord.mAppCompatController .getAppCompatLetterboxOverrides(); pw.println(prefix + " letterboxBackgroundColor=" + Integer.toHexString( @@ -276,12 +276,12 @@ class AppCompatLetterboxPolicy { final AppCompatLetterboxOverrides letterboxOverrides = mActivityRecord .mAppCompatController.getAppCompatLetterboxOverrides(); final AppCompatReachabilityPolicy reachabilityPolicy = mActivityRecord - .mAppCompatController.getAppCompatReachabilityPolicy(); + .mAppCompatController.getReachabilityPolicy(); mLetterbox = new Letterbox(() -> mActivityRecord.makeChildSurface(null), mActivityRecord.mWmService.mTransactionFactory, reachabilityPolicy, letterboxOverrides, this::getLetterboxParentSurface); - mActivityRecord.mAppCompatController.getAppCompatReachabilityPolicy() + mActivityRecord.mAppCompatController.getReachabilityPolicy() .setLetterboxInnerBoundsSupplier(mLetterbox::getInnerFrame); } final Point letterboxPosition = new Point(); @@ -291,7 +291,7 @@ class AppCompatLetterboxPolicy { final Rect innerFrame = new Rect(); calculateLetterboxInnerBounds(mActivityRecord, w, innerFrame); mLetterbox.layout(spaceToFill, innerFrame, letterboxPosition); - if (mActivityRecord.mAppCompatController.getAppCompatReachabilityOverrides() + if (mActivityRecord.mAppCompatController.getReachabilityOverrides() .isDoubleTapEvent()) { // We need to notify Shell that letterbox position has changed. mActivityRecord.getTask().dispatchTaskInfoChangedIfNeeded(true /* force */); @@ -321,7 +321,7 @@ class AppCompatLetterboxPolicy { mLetterbox.destroy(); mLetterbox = null; } - mActivityRecord.mAppCompatController.getAppCompatReachabilityPolicy() + mActivityRecord.mAppCompatController.getReachabilityPolicy() .setLetterboxInnerBoundsSupplier(null); } @@ -415,7 +415,7 @@ class AppCompatLetterboxPolicy { calculateLetterboxPosition(mActivityRecord, mLetterboxPosition); calculateLetterboxOuterBounds(mActivityRecord, mOuterBounds); calculateLetterboxInnerBounds(mActivityRecord, w, mInnerBounds); - mActivityRecord.mAppCompatController.getAppCompatReachabilityPolicy() + mActivityRecord.mAppCompatController.getReachabilityPolicy() .setLetterboxInnerBoundsSupplier(() -> mInnerBounds); } @@ -438,7 +438,7 @@ class AppCompatLetterboxPolicy { mLetterboxPosition.set(0, 0); mInnerBounds.setEmpty(); mOuterBounds.setEmpty(); - mActivityRecord.mAppCompatController.getAppCompatReachabilityPolicy() + mActivityRecord.mAppCompatController.getReachabilityPolicy() .setLetterboxInnerBoundsSupplier(null); } diff --git a/services/core/java/com/android/server/wm/AppCompatOverrides.java b/services/core/java/com/android/server/wm/AppCompatOverrides.java index 58b37becc373..9effae6aa640 100644 --- a/services/core/java/com/android/server/wm/AppCompatOverrides.java +++ b/services/core/java/com/android/server/wm/AppCompatOverrides.java @@ -37,7 +37,7 @@ public class AppCompatOverrides { @NonNull private final AppCompatResizeOverrides mResizeOverrides; @NonNull - private final AppCompatReachabilityOverrides mAppCompatReachabilityOverrides; + private final AppCompatReachabilityOverrides mReachabilityOverrides; @NonNull private final AppCompatLetterboxOverrides mAppCompatLetterboxOverrides; @@ -50,11 +50,11 @@ public class AppCompatOverrides { appCompatConfiguration, optPropBuilder); mAppCompatOrientationOverrides = new AppCompatOrientationOverrides(activityRecord, appCompatConfiguration, optPropBuilder, mAppCompatCameraOverrides); - mAppCompatReachabilityOverrides = new AppCompatReachabilityOverrides(activityRecord, + mReachabilityOverrides = new AppCompatReachabilityOverrides(activityRecord, appCompatConfiguration, appCompatDeviceStateQuery); mAppCompatAspectRatioOverrides = new AppCompatAspectRatioOverrides(activityRecord, appCompatConfiguration, optPropBuilder, appCompatDeviceStateQuery, - mAppCompatReachabilityOverrides); + mReachabilityOverrides); mAppCompatFocusOverrides = new AppCompatFocusOverrides(activityRecord, appCompatConfiguration, optPropBuilder); mResizeOverrides = new AppCompatResizeOverrides(activityRecord, packageManager, @@ -89,8 +89,8 @@ public class AppCompatOverrides { } @NonNull - AppCompatReachabilityOverrides getAppCompatReachabilityOverrides() { - return mAppCompatReachabilityOverrides; + AppCompatReachabilityOverrides getReachabilityOverrides() { + return mReachabilityOverrides; } @NonNull diff --git a/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java b/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java index d03a80387657..087edc184b6f 100644 --- a/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java +++ b/services/core/java/com/android/server/wm/AppCompatReachabilityPolicy.java @@ -77,7 +77,7 @@ class AppCompatReachabilityPolicy { void dump(@NonNull PrintWriter pw, @NonNull String prefix) { final AppCompatReachabilityOverrides reachabilityOverrides = - mActivityRecord.mAppCompatController.getAppCompatReachabilityOverrides(); + mActivityRecord.mAppCompatController.getReachabilityOverrides(); pw.println(prefix + " isVerticalThinLetterboxed=" + reachabilityOverrides .isVerticalThinLetterboxed()); pw.println(prefix + " isHorizontalThinLetterboxed=" + reachabilityOverrides @@ -96,7 +96,7 @@ class AppCompatReachabilityPolicy { private void handleHorizontalDoubleTap(int x) { final AppCompatReachabilityOverrides reachabilityOverrides = - mActivityRecord.mAppCompatController.getAppCompatReachabilityOverrides(); + mActivityRecord.mAppCompatController.getReachabilityOverrides(); if (!reachabilityOverrides.isHorizontalReachabilityEnabled() || mActivityRecord.isInTransition()) { return; @@ -142,7 +142,7 @@ class AppCompatReachabilityPolicy { private void handleVerticalDoubleTap(int y) { final AppCompatReachabilityOverrides reachabilityOverrides = - mActivityRecord.mAppCompatController.getAppCompatReachabilityOverrides(); + mActivityRecord.mAppCompatController.getReachabilityOverrides(); if (!reachabilityOverrides.isVerticalReachabilityEnabled() || mActivityRecord.isInTransition()) { return; diff --git a/services/core/java/com/android/server/wm/AppCompatUtils.java b/services/core/java/com/android/server/wm/AppCompatUtils.java index 9f88bc952351..e28dddc496e1 100644 --- a/services/core/java/com/android/server/wm/AppCompatUtils.java +++ b/services/core/java/com/android/server/wm/AppCompatUtils.java @@ -138,7 +138,7 @@ final class AppCompatUtils { return; } final AppCompatReachabilityOverrides reachabilityOverrides = top.mAppCompatController - .getAppCompatReachabilityOverrides(); + .getReachabilityOverrides(); final boolean isTopActivityResumed = top.getOrganizedTask() == task && top.isState(RESUMED); final boolean isTopActivityVisible = top.getOrganizedTask() == task && top.isVisible(); // Whether the direct top activity is in size compat mode. diff --git a/services/core/java/com/android/server/wm/ContentRecorder.java b/services/core/java/com/android/server/wm/ContentRecorder.java index a4e58ef923b8..d6ae65193121 100644 --- a/services/core/java/com/android/server/wm/ContentRecorder.java +++ b/services/core/java/com/android/server/wm/ContentRecorder.java @@ -108,9 +108,7 @@ final class ContentRecorder implements WindowContainerListener { ContentRecorder(@NonNull DisplayContent displayContent) { this(displayContent, new RemoteMediaProjectionManagerWrapper(displayContent.mDisplayId), - new DisplayManagerFlags().isConnectedDisplayManagementEnabled() - && !new DisplayManagerFlags() - .isPixelAnisotropyCorrectionInLogicalDisplayEnabled() + !new DisplayManagerFlags().isPixelAnisotropyCorrectionInLogicalDisplayEnabled() && displayContent.getDisplayInfo().type == Display.TYPE_EXTERNAL); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 3c6778ecbb30..92e0931993d1 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -10177,9 +10177,10 @@ public class WindowManagerService extends IWindowManager.Stub throw new SecurityException("Access denied to process: " + pid + ", must have permission " + Manifest.permission.ACCESS_FPS_COUNTER); } - - if (mRoot.anyTaskForId(taskId) == null) { - throw new IllegalArgumentException("no task with taskId: " + taskId); + synchronized (mGlobalLock) { + if (mRoot.anyTaskForId(taskId) == null) { + throw new IllegalArgumentException("no task with taskId: " + taskId); + } } mTaskFpsCallbackController.registerListener(taskId, callback); diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java index a9ad435762ad..02e5470e8673 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java @@ -415,7 +415,6 @@ public class DisplayManagerServiceTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(false); mLocalServiceKeeperRule.overrideLocalService( InputManagerInternal.class, mMockInputManagerInternal); @@ -2797,30 +2796,7 @@ public class DisplayManagerServiceTest { } @Test - public void testConnectExternalDisplay_withoutDisplayManagement_shouldAddDisplay() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(false); - manageDisplaysPermission(/* granted= */ true); - DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); - DisplayManagerService.BinderService bs = displayManager.new BinderService(); - LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper(); - FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(); - bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS); - callback.expectsEvent(EVENT_DISPLAY_ADDED); - - FakeDisplayDevice displayDevice = - createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL); - callback.waitForExpectedEvent(); - - LogicalDisplay display = - logicalDisplayMapper.getDisplayLocked(displayDevice, /* includeDisabled= */ true); - assertThat(display.isEnabledLocked()).isTrue(); - assertThat(callback.receivedEvents()).containsExactly(EVENT_DISPLAY_ADDED); - - } - - @Test - public void testConnectExternalDisplay_withDisplayManagement_shouldDisableDisplay() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); + public void testConnectExternalDisplay_shouldDisableDisplay() { manageDisplaysPermission(/* granted= */ true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); displayManager.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); @@ -2849,9 +2825,8 @@ public class DisplayManagerServiceTest { } @Test - public void testConnectExternalDisplay_withDisplayManagementAndSysprop_shouldEnableDisplay() { + public void testConnectExternalDisplay_withSysprop_shouldEnableDisplay() { Assume.assumeTrue(Build.IS_ENG || Build.IS_USERDEBUG); - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); doAnswer((Answer<Boolean>) invocationOnMock -> true) .when(() -> SystemProperties.getBoolean(ENABLE_ON_CONNECT, false)); manageDisplaysPermission(/* granted= */ true); @@ -2883,8 +2858,7 @@ public class DisplayManagerServiceTest { } @Test - public void testConnectExternalDisplay_withDisplayManagement_allowsEnableAndDisableDisplay() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); + public void testConnectExternalDisplay_allowsEnableAndDisableDisplay() { when(mMockFlags.isApplyDisplayChangedDuringDisplayAddedEnabled()).thenReturn(true); manageDisplaysPermission(/* granted= */ true); LocalServices.addService(WindowManagerPolicy.class, mMockedWindowManagerPolicy); @@ -2955,8 +2929,7 @@ public class DisplayManagerServiceTest { } @Test - public void testConnectInternalDisplay_withDisplayManagement_shouldConnectAndAddDisplay() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); + public void testConnectInternalDisplay_shouldConnectAndAddDisplay() { manageDisplaysPermission(/* granted= */ true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService bs = displayManager.new BinderService(); @@ -3011,7 +2984,7 @@ public class DisplayManagerServiceTest { DisplayManagerService.BinderService bs = displayManager.new BinderService(); LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper(); FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(); - bs.registerCallbackWithEventMask(callback, STANDARD_AND_CONNECTION_DISPLAY_EVENTS); + bs.registerCallbackWithEventMask(callback, STANDARD_DISPLAY_EVENTS); callback.expectsEvent(EVENT_DISPLAY_ADDED); FakeDisplayDevice displayDevice = @@ -3032,8 +3005,7 @@ public class DisplayManagerServiceTest { } @Test - public void testEnableExternalDisplay_withDisplayManagement_shouldSignalDisplayAdded() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); + public void testEnableExternalDisplay_shouldSignalDisplayAdded() { manageDisplaysPermission(/* granted= */ true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); displayManager.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); @@ -3062,8 +3034,7 @@ public class DisplayManagerServiceTest { } @Test - public void testEnableExternalDisplay_withoutPermission_shouldThrowException() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); + public void testEnableExternalDisplay_shouldThrowException() { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService bs = displayManager.new BinderService(); LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper(); @@ -3087,8 +3058,7 @@ public class DisplayManagerServiceTest { } @Test - public void testEnableInternalDisplay_withManageDisplays_shouldSignalAdded() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); + public void testEnableInternalDisplay_shouldSignalAdded() { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService bs = displayManager.new BinderService(); LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper(); @@ -3115,8 +3085,7 @@ public class DisplayManagerServiceTest { } @Test - public void testDisableInternalDisplay_withDisplayManagement_shouldSignalRemove() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); + public void testDisableInternalDisplay_shouldSignalRemove() { DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService bs = displayManager.new BinderService(); LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper(); @@ -3140,7 +3109,6 @@ public class DisplayManagerServiceTest { @Test public void testDisableExternalDisplay_shouldSignalDisplayRemoved() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService bs = displayManager.new BinderService(); LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper(); @@ -3181,7 +3149,6 @@ public class DisplayManagerServiceTest { @Test public void testDisableExternalDisplay_withoutPermission_shouldThrowException() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService bs = displayManager.new BinderService(); LogicalDisplayMapper logicalDisplayMapper = displayManager.getLogicalDisplayMapper(); @@ -3207,7 +3174,6 @@ public class DisplayManagerServiceTest { @Test public void testRemoveExternalDisplay_whenDisabled_shouldSignalDisconnected() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); manageDisplaysPermission(/* granted= */ true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); displayManager.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); @@ -3244,7 +3210,6 @@ public class DisplayManagerServiceTest { @Test public void testRegisterCallback_withoutPermission_shouldThrow() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService bs = displayManager.new BinderService(); FakeDisplayManagerCallback callback = new FakeDisplayManagerCallback(); @@ -3255,7 +3220,6 @@ public class DisplayManagerServiceTest { @Test public void testRemoveExternalDisplay_whenEnabled_shouldSignalRemovedAndDisconnected() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); manageDisplaysPermission(/* granted= */ true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); displayManager.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); @@ -3288,7 +3252,6 @@ public class DisplayManagerServiceTest { @Test public void testRemoveInternalDisplay_whenEnabled_shouldSignalRemovedAndDisconnected() { - when(mMockFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); manageDisplaysPermission(/* granted= */ true); DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector); DisplayManagerService.BinderService bs = displayManager.new BinderService(); diff --git a/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java b/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java index 782262d3f7c9..a48a88cecbc2 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/ExternalDisplayPolicyTest.java @@ -22,7 +22,6 @@ import static android.view.Display.TYPE_INTERNAL; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assume.assumeFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -47,7 +46,6 @@ import com.android.server.display.feature.DisplayManagerFlags; import com.android.server.display.notifications.DisplayNotificationManager; import com.android.server.testutils.TestHandler; -import com.google.testing.junit.testparameterinjector.TestParameter; import com.google.testing.junit.testparameterinjector.TestParameterInjector; import org.junit.Before; @@ -124,7 +122,6 @@ public class ExternalDisplayPolicyTest { public void setup() throws Exception { MockitoAnnotations.initMocks(this); mHandler = new TestHandler(/*callback=*/ null); - when(mMockedFlags.isConnectedDisplayManagementEnabled()).thenReturn(true); when(mMockedFlags.isConnectedDisplayErrorHandlingEnabled()).thenReturn(true); when(mMockedInjector.getFlags()).thenReturn(mMockedFlags); when(mMockedInjector.getLogicalDisplayMapper()).thenReturn(mMockedLogicalDisplayMapper); @@ -173,16 +170,6 @@ public class ExternalDisplayPolicyTest { } @Test - public void testTryEnableExternalDisplay_featureDisabled(@TestParameter final boolean enable) { - when(mMockedFlags.isConnectedDisplayManagementEnabled()).thenReturn(false); - mExternalDisplayPolicy.setExternalDisplayEnabledLocked(mMockedLogicalDisplay, enable); - mHandler.flush(); - verify(mMockedLogicalDisplayMapper, never()).setDisplayEnabledLocked(any(), anyBoolean()); - verify(mMockedDisplayNotificationManager, never()) - .onHighTemperatureExternalDisplayNotAllowed(); - } - - @Test public void testTryDisableExternalDisplay_criticalThermalCondition() throws RemoteException { // Disallow external displays due to thermals. setTemperature(registerThermalListener(), List.of(CRITICAL_TEMPERATURE)); @@ -278,21 +265,6 @@ public class ExternalDisplayPolicyTest { } @Test - public void testNoThermalListenerRegistered_featureDisabled( - @TestParameter final boolean isConnectedDisplayManagementEnabled, - @TestParameter final boolean isErrorHandlingEnabled) throws RemoteException { - assumeFalse(isConnectedDisplayManagementEnabled && isErrorHandlingEnabled); - when(mMockedFlags.isConnectedDisplayManagementEnabled()).thenReturn( - isConnectedDisplayManagementEnabled); - when(mMockedFlags.isConnectedDisplayErrorHandlingEnabled()).thenReturn( - isErrorHandlingEnabled); - - mExternalDisplayPolicy.onBootCompleted(); - verify(mMockedThermalService, never()).registerThermalEventListenerWithType( - any(), anyInt()); - } - - @Test public void testOnCriticalTemperature_disallowAndAllowExternalDisplay() throws RemoteException { final var thermalListener = registerThermalListener(); diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java index 0dbb6ba58b3c..7d3cd8a8a9ae 100644 --- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -222,7 +222,6 @@ public class LogicalDisplayMapperTest { when(mSyntheticModeManagerMock.createAppSupportedModes(any(), any(), anyBoolean())) .thenAnswer(AdditionalAnswers.returnsSecondArg()); - when(mFlagsMock.isConnectedDisplayManagementEnabled()).thenReturn(false); mLooper = new TestLooper(); mHandler = new Handler(mLooper.getLooper()); mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mFoldSettingProviderMock, @@ -351,8 +350,7 @@ public class LogicalDisplayMapperTest { } @Test - public void testDisplayDeviceAddAndRemove_withDisplayManagement() { - when(mFlagsMock.isConnectedDisplayManagementEnabled()).thenReturn(true); + public void testDisplayDeviceAddAndRemove() { DisplayDevice device = createDisplayDevice(TYPE_INTERNAL, 600, 800, FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); @@ -390,8 +388,7 @@ public class LogicalDisplayMapperTest { } @Test - public void testDisplayDisableEnable_withDisplayManagement() { - when(mFlagsMock.isConnectedDisplayManagementEnabled()).thenReturn(true); + public void testDisplayDisableEnable() { DisplayDevice device = createDisplayDevice(TYPE_INTERNAL, 600, 800, FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY); LogicalDisplay displayAdded = add(device); @@ -1350,9 +1347,14 @@ public class LogicalDisplayMapperTest { ArgumentCaptor<LogicalDisplay> displayCaptor = ArgumentCaptor.forClass(LogicalDisplay.class); verify(mListenerMock).onLogicalDisplayEventLocked( - displayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_ADDED)); + displayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_CONNECTED)); + LogicalDisplay display = displayCaptor.getValue(); + if (display.isEnabledLocked()) { + verify(mListenerMock).onLogicalDisplayEventLocked( + eq(display), eq(LOGICAL_DISPLAY_EVENT_ADDED)); + } clearInvocations(mListenerMock); - return displayCaptor.getValue(); + return display; } private void testDisplayDeviceAddAndRemove_NonInternal(int type) { diff --git a/services/tests/timetests/src/com/android/server/timezonedetector/ConfigInternalForTests.java b/services/tests/timetests/src/com/android/server/timezonedetector/ConfigInternalForTests.java new file mode 100644 index 000000000000..47e3dc85f6d0 --- /dev/null +++ b/services/tests/timetests/src/com/android/server/timezonedetector/ConfigInternalForTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.timezonedetector; + +import android.annotation.UserIdInt; + +public final class ConfigInternalForTests { + + static final @UserIdInt int USER_ID = 9876; + + static final ConfigurationInternal CONFIG_USER_RESTRICTED_AUTO_DISABLED = + new ConfigurationInternal.Builder() + .setUserId(USER_ID) + .setTelephonyDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) + .setTelephonyFallbackSupported(false) + .setGeoDetectionRunInBackgroundEnabled(false) + .setEnhancedMetricsCollectionEnabled(false) + .setUserConfigAllowed(false) + .setAutoDetectionEnabledSetting(false) + .setLocationEnabledSetting(true) + .setGeoDetectionEnabledSetting(false) + .build(); + + static final ConfigurationInternal CONFIG_USER_RESTRICTED_AUTO_ENABLED = + new ConfigurationInternal.Builder() + .setUserId(USER_ID) + .setTelephonyDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) + .setTelephonyFallbackSupported(false) + .setGeoDetectionRunInBackgroundEnabled(false) + .setEnhancedMetricsCollectionEnabled(false) + .setUserConfigAllowed(false) + .setAutoDetectionEnabledSetting(true) + .setLocationEnabledSetting(true) + .setGeoDetectionEnabledSetting(true) + .build(); + + static final ConfigurationInternal CONFIG_AUTO_DETECT_NOT_SUPPORTED = + new ConfigurationInternal.Builder() + .setUserId(USER_ID) + .setTelephonyDetectionFeatureSupported(false) + .setGeoDetectionFeatureSupported(false) + .setTelephonyFallbackSupported(false) + .setGeoDetectionRunInBackgroundEnabled(false) + .setEnhancedMetricsCollectionEnabled(false) + .setUserConfigAllowed(true) + .setAutoDetectionEnabledSetting(false) + .setLocationEnabledSetting(true) + .setGeoDetectionEnabledSetting(false) + .build(); + + static final ConfigurationInternal CONFIG_AUTO_DISABLED_GEO_DISABLED = + new ConfigurationInternal.Builder() + .setUserId(USER_ID) + .setTelephonyDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) + .setTelephonyFallbackSupported(false) + .setGeoDetectionRunInBackgroundEnabled(false) + .setEnhancedMetricsCollectionEnabled(false) + .setUserConfigAllowed(true) + .setAutoDetectionEnabledSetting(false) + .setLocationEnabledSetting(true) + .setGeoDetectionEnabledSetting(false) + .build(); + + static final ConfigurationInternal CONFIG_AUTO_ENABLED_GEO_DISABLED = + new ConfigurationInternal.Builder() + .setUserId(USER_ID) + .setTelephonyDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) + .setTelephonyFallbackSupported(false) + .setGeoDetectionRunInBackgroundEnabled(false) + .setEnhancedMetricsCollectionEnabled(false) + .setUserConfigAllowed(true) + .setAutoDetectionEnabledSetting(true) + .setLocationEnabledSetting(true) + .setGeoDetectionEnabledSetting(false) + .build(); + + static final ConfigurationInternal CONFIG_AUTO_ENABLED_GEO_ENABLED = + new ConfigurationInternal.Builder() + .setUserId(USER_ID) + .setTelephonyDetectionFeatureSupported(true) + .setGeoDetectionFeatureSupported(true) + .setTelephonyFallbackSupported(false) + .setGeoDetectionRunInBackgroundEnabled(false) + .setEnhancedMetricsCollectionEnabled(false) + .setUserConfigAllowed(true) + .setAutoDetectionEnabledSetting(true) + .setLocationEnabledSetting(true) + .setGeoDetectionEnabledSetting(true) + .build(); +} diff --git a/services/tests/timetests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java b/services/tests/timetests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java index fc6afe486187..aeb4d9a19ff0 100644 --- a/services/tests/timetests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java +++ b/services/tests/timetests/src/com/android/server/timezonedetector/FakeServiceConfigAccessor.java @@ -31,7 +31,7 @@ import java.util.Optional; /** * A partially implemented, fake implementation of ServiceConfigAccessor for tests. * - * <p>This class has rudamentary support for multiple users, but unlike the real thing, it doesn't + * <p>This class has rudimentary support for multiple users, but unlike the real thing, it doesn't * simulate that some settings are global and shared between users. It also delivers config updates * synchronously. */ diff --git a/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java index e52e8b60a61d..47a9b2c47173 100644 --- a/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java +++ b/services/tests/timetests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java @@ -35,6 +35,12 @@ import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_U import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH; import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_LOW; +import static com.android.server.timezonedetector.ConfigInternalForTests.CONFIG_AUTO_DETECT_NOT_SUPPORTED; +import static com.android.server.timezonedetector.ConfigInternalForTests.CONFIG_AUTO_DISABLED_GEO_DISABLED; +import static com.android.server.timezonedetector.ConfigInternalForTests.CONFIG_AUTO_ENABLED_GEO_DISABLED; +import static com.android.server.timezonedetector.ConfigInternalForTests.CONFIG_AUTO_ENABLED_GEO_ENABLED; +import static com.android.server.timezonedetector.ConfigInternalForTests.CONFIG_USER_RESTRICTED_AUTO_ENABLED; +import static com.android.server.timezonedetector.ConfigInternalForTests.USER_ID; import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGH; import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_HIGHEST; import static com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.TELEPHONY_SCORE_LOW; @@ -68,6 +74,7 @@ import android.app.timezonedetector.TelephonyTimeZoneSuggestion; import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType; import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality; import android.service.timezone.TimeZoneProviderStatus; +import android.util.IndentingPrintWriter; import com.android.server.SystemTimeZone.TimeZoneConfidence; import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedTelephonyTimeZoneSuggestion; @@ -82,6 +89,7 @@ import org.junit.runner.RunWith; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.function.Function; @@ -92,7 +100,6 @@ import java.util.function.Function; @RunWith(JUnitParamsRunner.class) public class TimeZoneDetectorStrategyImplTest { - private static final @UserIdInt int USER_ID = 9876; private static final long ARBITRARY_ELAPSED_REALTIME_MILLIS = 1234; /** A time zone used for initialization that does not occur elsewhere in tests. */ private static final String ARBITRARY_TIME_ZONE_ID = "Etc/UTC"; @@ -101,7 +108,7 @@ public class TimeZoneDetectorStrategyImplTest { // Telephony test cases are ordered so that each successive one is of the same or higher score // than the previous. - private static final TelephonyTestCase[] TELEPHONY_TEST_CASES = new TelephonyTestCase[] { + private static final TelephonyTestCase[] TELEPHONY_TEST_CASES = new TelephonyTestCase[]{ newTelephonyTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY, QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS, TELEPHONY_SCORE_LOW), newTelephonyTestCase(MATCH_TYPE_NETWORK_COUNTRY_ONLY, @@ -118,90 +125,6 @@ public class TimeZoneDetectorStrategyImplTest { TELEPHONY_SCORE_HIGHEST), }; - private static final ConfigurationInternal CONFIG_USER_RESTRICTED_AUTO_DISABLED = - new ConfigurationInternal.Builder() - .setUserId(USER_ID) - .setTelephonyDetectionFeatureSupported(true) - .setGeoDetectionFeatureSupported(true) - .setTelephonyFallbackSupported(false) - .setGeoDetectionRunInBackgroundEnabled(false) - .setEnhancedMetricsCollectionEnabled(false) - .setUserConfigAllowed(false) - .setAutoDetectionEnabledSetting(false) - .setLocationEnabledSetting(true) - .setGeoDetectionEnabledSetting(false) - .build(); - - private static final ConfigurationInternal CONFIG_USER_RESTRICTED_AUTO_ENABLED = - new ConfigurationInternal.Builder() - .setUserId(USER_ID) - .setTelephonyDetectionFeatureSupported(true) - .setGeoDetectionFeatureSupported(true) - .setTelephonyFallbackSupported(false) - .setGeoDetectionRunInBackgroundEnabled(false) - .setEnhancedMetricsCollectionEnabled(false) - .setUserConfigAllowed(false) - .setAutoDetectionEnabledSetting(true) - .setLocationEnabledSetting(true) - .setGeoDetectionEnabledSetting(true) - .build(); - - private static final ConfigurationInternal CONFIG_AUTO_DETECT_NOT_SUPPORTED = - new ConfigurationInternal.Builder() - .setUserId(USER_ID) - .setTelephonyDetectionFeatureSupported(false) - .setGeoDetectionFeatureSupported(false) - .setTelephonyFallbackSupported(false) - .setGeoDetectionRunInBackgroundEnabled(false) - .setEnhancedMetricsCollectionEnabled(false) - .setUserConfigAllowed(true) - .setAutoDetectionEnabledSetting(false) - .setLocationEnabledSetting(true) - .setGeoDetectionEnabledSetting(false) - .build(); - - private static final ConfigurationInternal CONFIG_AUTO_DISABLED_GEO_DISABLED = - new ConfigurationInternal.Builder() - .setUserId(USER_ID) - .setTelephonyDetectionFeatureSupported(true) - .setGeoDetectionFeatureSupported(true) - .setTelephonyFallbackSupported(false) - .setGeoDetectionRunInBackgroundEnabled(false) - .setEnhancedMetricsCollectionEnabled(false) - .setUserConfigAllowed(true) - .setAutoDetectionEnabledSetting(false) - .setLocationEnabledSetting(true) - .setGeoDetectionEnabledSetting(false) - .build(); - - private static final ConfigurationInternal CONFIG_AUTO_ENABLED_GEO_DISABLED = - new ConfigurationInternal.Builder() - .setUserId(USER_ID) - .setTelephonyDetectionFeatureSupported(true) - .setGeoDetectionFeatureSupported(true) - .setTelephonyFallbackSupported(false) - .setGeoDetectionRunInBackgroundEnabled(false) - .setEnhancedMetricsCollectionEnabled(false) - .setUserConfigAllowed(true) - .setAutoDetectionEnabledSetting(true) - .setLocationEnabledSetting(true) - .setGeoDetectionEnabledSetting(false) - .build(); - - private static final ConfigurationInternal CONFIG_AUTO_ENABLED_GEO_ENABLED = - new ConfigurationInternal.Builder() - .setUserId(USER_ID) - .setTelephonyDetectionFeatureSupported(true) - .setGeoDetectionFeatureSupported(true) - .setTelephonyFallbackSupported(false) - .setGeoDetectionRunInBackgroundEnabled(false) - .setEnhancedMetricsCollectionEnabled(false) - .setUserConfigAllowed(true) - .setAutoDetectionEnabledSetting(true) - .setLocationEnabledSetting(true) - .setGeoDetectionEnabledSetting(true) - .build(); - private static final TelephonyTimeZoneAlgorithmStatus TELEPHONY_ALGORITHM_RUNNING_STATUS = new TelephonyTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING); @@ -421,7 +344,7 @@ public class TimeZoneDetectorStrategyImplTest { new QualifiedTelephonyTimeZoneSuggestion(slotIndex1TimeZoneSuggestion, TELEPHONY_SCORE_NONE); script.verifyLatestQualifiedTelephonySuggestionReceived( - SLOT_INDEX1, expectedSlotIndex1ScoredSuggestion) + SLOT_INDEX1, expectedSlotIndex1ScoredSuggestion) .verifyLatestQualifiedTelephonySuggestionReceived(SLOT_INDEX2, null); assertEquals(expectedSlotIndex1ScoredSuggestion, mTimeZoneDetectorStrategy.findBestTelephonySuggestionForTests()); @@ -629,7 +552,7 @@ public class TimeZoneDetectorStrategyImplTest { */ @Test public void testTelephonySuggestionMultipleSlotIndexSuggestionScoringAndSlotIndexBias() { - String[] zoneIds = { "Europe/London", "Europe/Paris" }; + String[] zoneIds = {"Europe/London", "Europe/Paris"}; TelephonyTimeZoneSuggestion emptySlotIndex1Suggestion = createEmptySlotIndex1Suggestion(); TelephonyTimeZoneSuggestion emptySlotIndex2Suggestion = createEmptySlotIndex2Suggestion(); QualifiedTelephonyTimeZoneSuggestion expectedEmptySlotIndex1ScoredSuggestion = @@ -672,7 +595,7 @@ public class TimeZoneDetectorStrategyImplTest { // Assert internal service state. script.verifyLatestQualifiedTelephonySuggestionReceived( - SLOT_INDEX1, expectedZoneSlotIndex1ScoredSuggestion) + SLOT_INDEX1, expectedZoneSlotIndex1ScoredSuggestion) .verifyLatestQualifiedTelephonySuggestionReceived( SLOT_INDEX2, expectedEmptySlotIndex2ScoredSuggestion); assertEquals(expectedZoneSlotIndex1ScoredSuggestion, @@ -805,14 +728,14 @@ public class TimeZoneDetectorStrategyImplTest { boolean bypassUserPolicyChecks = false; boolean expectedResult = true; script.simulateManualTimeZoneSuggestion( - USER_ID, manualSuggestion, bypassUserPolicyChecks, expectedResult) + USER_ID, manualSuggestion, bypassUserPolicyChecks, expectedResult) .verifyTimeZoneChangedAndReset(manualSuggestion); assertEquals(manualSuggestion, mTimeZoneDetectorStrategy.getLatestManualSuggestion()); } @Test - @Parameters({ "true,true", "true,false", "false,true", "false,false" }) + @Parameters({"true,true", "true,false", "false,true", "false,false"}) public void testManualSuggestion_autoTimeEnabled_userRestrictions( boolean userConfigAllowed, boolean bypassUserPolicyChecks) { ConfigurationInternal config = @@ -834,7 +757,7 @@ public class TimeZoneDetectorStrategyImplTest { } @Test - @Parameters({ "true,true", "true,false", "false,true", "false,false" }) + @Parameters({"true,true", "true,false", "false,true", "false,false"}) public void testManualSuggestion_autoTimeDisabled_userRestrictions( boolean userConfigAllowed, boolean bypassUserPolicyChecks) { ConfigurationInternal config = @@ -849,7 +772,7 @@ public class TimeZoneDetectorStrategyImplTest { ManualTimeZoneSuggestion manualSuggestion = createManualSuggestion("Europe/Paris"); boolean expectedResult = userConfigAllowed || bypassUserPolicyChecks; script.simulateManualTimeZoneSuggestion( - USER_ID, manualSuggestion, bypassUserPolicyChecks, expectedResult); + USER_ID, manualSuggestion, bypassUserPolicyChecks, expectedResult); if (expectedResult) { script.verifyTimeZoneChangedAndReset(manualSuggestion); assertEquals(manualSuggestion, mTimeZoneDetectorStrategy.getLatestManualSuggestion()); @@ -1258,7 +1181,6 @@ public class TimeZoneDetectorStrategyImplTest { script.simulateLocationAlgorithmEvent(locationAlgorithmEvent) .verifyTimeZoneChangedAndReset(locationAlgorithmEvent) .verifyTelephonyFallbackIsEnabled(false); - } // Demonstrate what happens when geolocation is uncertain when telephony fallback is @@ -1569,7 +1491,7 @@ public class TimeZoneDetectorStrategyImplTest { boolean bypassUserPolicyChecks = false; boolean expectedResult = true; script.simulateManualTimeZoneSuggestion( - USER_ID, manualSuggestion, bypassUserPolicyChecks, expectedResult) + USER_ID, manualSuggestion, bypassUserPolicyChecks, expectedResult) .verifyTimeZoneChangedAndReset(manualSuggestion); expectedDeviceTimeZoneId = manualSuggestion.getZoneId(); assertMetricsState(expectedInternalConfig, expectedDeviceTimeZoneId, @@ -1880,6 +1802,7 @@ public class TimeZoneDetectorStrategyImplTest { boolean actualResult = mTimeZoneDetectorStrategy.suggestManualTimeZone( userId, manualTimeZoneSuggestion, bypassUserPolicyChecks); assertEquals(expectedResult, actualResult); + return this; } @@ -2001,4 +1924,34 @@ public class TimeZoneDetectorStrategyImplTest { return new TelephonyTestCase(matchType, quality, expectedScore); } + static class FakeTimeZoneChangeEventListener implements TimeZoneChangeListener { + private final List<TimeZoneChangeEvent> mEvents = new ArrayList<>(); + + FakeTimeZoneChangeEventListener() { + } + + @Override + public void process(TimeZoneChangeEvent event) { + mEvents.add(event); + } + + public List<TimeZoneChangeEvent> getTimeZoneChangeEvents() { + return mEvents; + } + + @Override + public void dump(IndentingPrintWriter ipw) { + // No-op for tests + } + } + + private static void assertEmpty(Collection<?> collection) { + assertTrue( + "Expected empty, but contains (" + collection.size() + ") elements: " + collection, + collection.isEmpty()); + } + + private static void assertNotEmpty(Collection<?> collection) { + assertFalse("Expected not empty: " + collection, collection.isEmpty()); + } } diff --git a/services/tests/vibrator/src/com/android/server/vibrator/BasicToPwleSegmentAdapterTest.java b/services/tests/vibrator/src/com/android/server/vibrator/BasicToPwleSegmentAdapterTest.java new file mode 100644 index 000000000000..09f573cd1ee0 --- /dev/null +++ b/services/tests/vibrator/src/com/android/server/vibrator/BasicToPwleSegmentAdapterTest.java @@ -0,0 +1,158 @@ +/* + * 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.vibrator; + +import static com.google.common.truth.Truth.assertThat; + +import android.hardware.vibrator.IVibrator; +import android.os.VibratorInfo; +import android.os.vibrator.BasicPwleSegment; +import android.os.vibrator.Flags; +import android.os.vibrator.PwleSegment; +import android.os.vibrator.StepSegment; +import android.os.vibrator.VibrationEffectSegment; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.IntStream; + +public class BasicToPwleSegmentAdapterTest { + + private static final float TEST_RESONANT_FREQUENCY = 150; + private static final float[] TEST_FREQUENCIES = + new float[]{90f, 120f, 150f, 60f, 30f, 210f, 270f, 300f, 240f, 180f}; + private static final float[] TEST_OUTPUT_ACCELERATIONS = + new float[]{1.2f, 1.8f, 2.4f, 0.6f, 0.1f, 2.2f, 1.0f, 0.5f, 1.9f, 3.0f}; + + private static final VibratorInfo.FrequencyProfile TEST_FREQUENCY_PROFILE = + new VibratorInfo.FrequencyProfile(TEST_RESONANT_FREQUENCY, TEST_FREQUENCIES, + TEST_OUTPUT_ACCELERATIONS); + + private static final VibratorInfo.FrequencyProfile EMPTY_FREQUENCY_PROFILE = + new VibratorInfo.FrequencyProfile(TEST_RESONANT_FREQUENCY, null, null); + + private BasicToPwleSegmentAdapter mAdapter; + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + @Before + public void setUp() throws Exception { + mAdapter = new BasicToPwleSegmentAdapter(); + } + + @Test + @DisableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) + public void testBasicPwleSegments_withFeatureFlagDisabled_returnsOriginalSegments() { + List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList( + // startIntensity, endIntensity, startSharpness, endSharpness, duration + new BasicPwleSegment(0.2f, 0.8f, 0.2f, 0.4f, 20), + new BasicPwleSegment(0.8f, 0.2f, 0.4f, 0.5f, 100), + new BasicPwleSegment(0.2f, 0.65f, 0.5f, 0.5f, 50))); + List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments); + + VibratorInfo vibratorInfo = createVibratorInfo( + TEST_FREQUENCY_PROFILE, IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2); + + assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ -1)) + .isEqualTo(-1); + assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ 1)) + .isEqualTo(1); + + assertThat(segments).isEqualTo(originalSegments); + } + + @Test + @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) + public void testBasicPwleSegments_noPwleCapability_returnsOriginalSegments() { + List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList( + // startIntensity, endIntensity, startSharpness, endSharpness, duration + new BasicPwleSegment(0.2f, 0.8f, 0.2f, 0.4f, 20), + new BasicPwleSegment(0.8f, 0.2f, 0.4f, 0.5f, 100), + new BasicPwleSegment(0.2f, 0.65f, 0.5f, 0.5f, 50))); + List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments); + + VibratorInfo vibratorInfo = createVibratorInfo(TEST_FREQUENCY_PROFILE); + + assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ -1)) + .isEqualTo(-1); + assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ 1)) + .isEqualTo(1); + + assertThat(segments).isEqualTo(originalSegments); + } + + @Test + @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) + public void testBasicPwleSegments_invalidFrequencyProfile_returnsOriginalSegments() { + List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList( + // startIntensity, endIntensity, startSharpness, endSharpness, duration + new BasicPwleSegment(0.2f, 0.8f, 0.2f, 0.4f, 20), + new BasicPwleSegment(0.8f, 0.2f, 0.4f, 0.5f, 100), + new BasicPwleSegment(0.2f, 0.65f, 0.5f, 0.5f, 50))); + List<VibrationEffectSegment> originalSegments = new ArrayList<>(segments); + VibratorInfo vibratorInfo = createVibratorInfo( + EMPTY_FREQUENCY_PROFILE, IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2); + + assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ -1)) + .isEqualTo(-1); + assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ 1)) + .isEqualTo(1); + + assertThat(segments).isEqualTo(originalSegments); + } + + @Test + @EnableFlags(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) + public void testBasicPwleSegments_withPwleCapability_adaptSegmentsCorrectly() { + List<VibrationEffectSegment> segments = new ArrayList<>(Arrays.asList( + new StepSegment(/* amplitude= */ 1, /* frequencyHz= */ 40f, /* duration= */ 100), + // startIntensity, endIntensity, startSharpness, endSharpness, duration + new BasicPwleSegment(0.0f, 1.0f, 0.0f, 1.0f, 100), + new BasicPwleSegment(0.0f, 1.0f, 0.0f, 1.0f, 100), + new BasicPwleSegment(0.0f, 1.0f, 0.0f, 1.0f, 100))); + List<VibrationEffectSegment> expectedSegments = Arrays.asList( + new StepSegment(/* amplitude= */ 1, /* frequencyHz= */ 40f, /* duration= */ 100), + // startAmplitude, endAmplitude, startFrequencyHz, endFrequencyHz, duration + new PwleSegment(0.0f, 1.0f, 30.0f, 300.0f, 100), + new PwleSegment(0.0f, 1.0f, 30.0f, 300.0f, 100), + new PwleSegment(0.0f, 1.0f, 30.0f, 300.0f, 100)); + VibratorInfo vibratorInfo = createVibratorInfo( + TEST_FREQUENCY_PROFILE, IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2); + + assertThat(mAdapter.adaptToVibrator(vibratorInfo, segments, /*repeatIndex= */ 1)) + .isEqualTo(1); + + assertThat(segments).isEqualTo(expectedSegments); + } + + private static VibratorInfo createVibratorInfo(VibratorInfo.FrequencyProfile frequencyProfile, + int... capabilities) { + return new VibratorInfo.Builder(0) + .setCapabilities(IntStream.of(capabilities).reduce((a, b) -> a | b).orElse(0)) + .setFrequencyProfile(frequencyProfile) + .build(); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityOverridesTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityOverridesTest.java index 463254caa845..50419d46f48f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityOverridesTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityOverridesTest.java @@ -159,8 +159,8 @@ public class AppCompatReachabilityOverridesTest extends WindowTestsBase { @Override void onPostActivityCreation(@NonNull ActivityRecord activity) { super.onPostActivityCreation(activity); - spyOn(activity.mAppCompatController.getAppCompatReachabilityOverrides()); - activity.mAppCompatController.getAppCompatReachabilityPolicy() + spyOn(activity.mAppCompatController.getReachabilityOverrides()); + activity.mAppCompatController.getReachabilityPolicy() .setLetterboxInnerBoundsSupplier(mLetterboxInnerBoundsSupplier); } @@ -196,7 +196,7 @@ public class AppCompatReachabilityOverridesTest extends WindowTestsBase { @NonNull private AppCompatReachabilityOverrides getAppCompatReachabilityOverrides() { - return activity().top().mAppCompatController.getAppCompatReachabilityOverrides(); + return activity().top().mAppCompatController.getReachabilityOverrides(); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityPolicyTest.java index ddc4de9cfd8a..09b8bce2c930 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatReachabilityPolicyTest.java @@ -246,8 +246,8 @@ public class AppCompatReachabilityPolicyTest extends WindowTestsBase { @Override void onPostActivityCreation(@NonNull ActivityRecord activity) { super.onPostActivityCreation(activity); - spyOn(activity.mAppCompatController.getAppCompatReachabilityOverrides()); - activity.mAppCompatController.getAppCompatReachabilityPolicy() + spyOn(activity.mAppCompatController.getReachabilityOverrides()); + activity.mAppCompatController.getReachabilityPolicy() .setLetterboxInnerBoundsSupplier(mLetterboxInnerBoundsSupplier); } @@ -281,12 +281,12 @@ public class AppCompatReachabilityPolicyTest extends WindowTestsBase { @NonNull private AppCompatReachabilityOverrides getAppCompatReachabilityOverrides() { - return activity().top().mAppCompatController.getAppCompatReachabilityOverrides(); + return activity().top().mAppCompatController.getReachabilityOverrides(); } @NonNull private AppCompatReachabilityPolicy getAppCompatReachabilityPolicy() { - return activity().top().mAppCompatController.getAppCompatReachabilityPolicy(); + return activity().top().mAppCompatController.getReachabilityPolicy(); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index 9d9f24cb50f2..d6080e08774e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -330,7 +330,7 @@ public class SizeCompatTests extends WindowTestsBase { if (horizontalReachability) { final Consumer<Integer> doubleClick = (Integer x) -> { - mActivity.mAppCompatController.getAppCompatReachabilityPolicy() + mActivity.mAppCompatController.getReachabilityPolicy() .handleDoubleTap(x, displayHeight / 2); mActivity.mRootWindowContainer.performSurfacePlacement(); }; @@ -360,7 +360,7 @@ public class SizeCompatTests extends WindowTestsBase { } else { final Consumer<Integer> doubleClick = (Integer y) -> { - mActivity.mAppCompatController.getAppCompatReachabilityPolicy() + mActivity.mAppCompatController.getReachabilityPolicy() .handleDoubleTap(displayWidth / 2, y); mActivity.mRootWindowContainer.performSurfacePlacement(); }; @@ -421,7 +421,7 @@ public class SizeCompatTests extends WindowTestsBase { final Consumer<Integer> doubleClick = (Integer y) -> { - activity.mAppCompatController.getAppCompatReachabilityPolicy() + activity.mAppCompatController.getReachabilityPolicy() .handleDoubleTap(dw / 2, y); activity.mRootWindowContainer.performSurfacePlacement(); }; @@ -3427,7 +3427,7 @@ public class SizeCompatTests extends WindowTestsBase { setUpAllowThinLetterboxed(/* thinLetterboxAllowed */ false); final AppCompatReachabilityOverrides reachabilityOverrides = - mActivity.mAppCompatController.getAppCompatReachabilityOverrides(); + mActivity.mAppCompatController.getReachabilityOverrides(); assertFalse(reachabilityOverrides.isVerticalReachabilityEnabled()); assertFalse(reachabilityOverrides.isHorizontalReachabilityEnabled()); } @@ -3451,7 +3451,7 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); // Horizontal reachability is disabled because the app is in split screen. - assertFalse(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + assertFalse(mActivity.mAppCompatController.getReachabilityOverrides() .isHorizontalReachabilityEnabled()); } @@ -3475,7 +3475,7 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(WINDOWING_MODE_MULTI_WINDOW, mActivity.getWindowingMode()); // Vertical reachability is disabled because the app is in split screen. - assertFalse(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + assertFalse(mActivity.mAppCompatController.getReachabilityOverrides() .isVerticalReachabilityEnabled()); } @@ -3498,7 +3498,7 @@ public class SizeCompatTests extends WindowTestsBase { // Vertical reachability is disabled because the app does not match parent width assertNotEquals(mActivity.getScreenResolvedBounds().width(), mActivity.mDisplayContent.getBounds().width()); - assertFalse(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + assertFalse(mActivity.mAppCompatController.getReachabilityOverrides() .isVerticalReachabilityEnabled()); } @@ -3516,7 +3516,7 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(new Rect(0, 0, 0, 0), mActivity.getBounds()); // Vertical reachability is still enabled as resolved bounds is not empty - assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + assertTrue(mActivity.mAppCompatController.getReachabilityOverrides() .isVerticalReachabilityEnabled()); } @@ -3533,7 +3533,7 @@ public class SizeCompatTests extends WindowTestsBase { assertEquals(new Rect(0, 0, 0, 0), mActivity.getBounds()); // Horizontal reachability is still enabled as resolved bounds is not empty - assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + assertTrue(mActivity.mAppCompatController.getReachabilityOverrides() .isHorizontalReachabilityEnabled()); } @@ -3548,7 +3548,7 @@ public class SizeCompatTests extends WindowTestsBase { prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, SCREEN_ORIENTATION_PORTRAIT); - assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + assertTrue(mActivity.mAppCompatController.getReachabilityOverrides() .isHorizontalReachabilityEnabled()); } @@ -3563,7 +3563,7 @@ public class SizeCompatTests extends WindowTestsBase { prepareMinAspectRatio(mActivity, OVERRIDE_MIN_ASPECT_RATIO_LARGE_VALUE, SCREEN_ORIENTATION_LANDSCAPE); - assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + assertTrue(mActivity.mAppCompatController.getReachabilityOverrides() .isVerticalReachabilityEnabled()); } @@ -3585,7 +3585,7 @@ public class SizeCompatTests extends WindowTestsBase { // Horizontal reachability is disabled because the app does not match parent height assertNotEquals(mActivity.getScreenResolvedBounds().height(), mActivity.mDisplayContent.getBounds().height()); - assertFalse(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + assertFalse(mActivity.mAppCompatController.getReachabilityOverrides() .isHorizontalReachabilityEnabled()); } @@ -3608,7 +3608,7 @@ public class SizeCompatTests extends WindowTestsBase { // Horizontal reachability is enabled because the app matches parent height assertEquals(mActivity.getScreenResolvedBounds().height(), mActivity.mDisplayContent.getBounds().height()); - assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + assertTrue(mActivity.mAppCompatController.getReachabilityOverrides() .isHorizontalReachabilityEnabled()); } @@ -3631,7 +3631,7 @@ public class SizeCompatTests extends WindowTestsBase { // Vertical reachability is enabled because the app matches parent width assertEquals(mActivity.getScreenResolvedBounds().width(), mActivity.mDisplayContent.getBounds().width()); - assertTrue(mActivity.mAppCompatController.getAppCompatReachabilityOverrides() + assertTrue(mActivity.mAppCompatController.getReachabilityOverrides() .isVerticalReachabilityEnabled()); } @@ -4315,7 +4315,7 @@ public class SizeCompatTests extends WindowTestsBase { // Make sure app doesn't jump to top (default tabletop position) when unfolding. assertEquals(1.0f, mActivity.mAppCompatController - .getAppCompatReachabilityOverrides().getVerticalPositionMultiplier(mActivity + .getReachabilityOverrides().getVerticalPositionMultiplier(mActivity .getParent().getConfiguration()), 0); // Simulate display fully open after unfolding. @@ -4323,7 +4323,7 @@ public class SizeCompatTests extends WindowTestsBase { doReturn(false).when(mActivity.mDisplayContent).inTransition(); assertEquals(1.0f, mActivity.mAppCompatController - .getAppCompatReachabilityOverrides().getVerticalPositionMultiplier(mActivity + .getReachabilityOverrides().getVerticalPositionMultiplier(mActivity .getParent().getConfiguration()), 0); } @@ -5028,7 +5028,7 @@ public class SizeCompatTests extends WindowTestsBase { private void setUpAllowThinLetterboxed(boolean thinLetterboxAllowed) { final AppCompatReachabilityOverrides reachabilityOverrides = - mActivity.mAppCompatController.getAppCompatReachabilityOverrides(); + mActivity.mAppCompatController.getReachabilityOverrides(); spyOn(reachabilityOverrides); doReturn(thinLetterboxAllowed).when(reachabilityOverrides) .allowVerticalReachabilityForThinLetterbox(); diff --git a/telephony/java/android/telephony/satellite/SatelliteManager.java b/telephony/java/android/telephony/satellite/SatelliteManager.java index 63a12816f783..b7b209b78300 100644 --- a/telephony/java/android/telephony/satellite/SatelliteManager.java +++ b/telephony/java/android/telephony/satellite/SatelliteManager.java @@ -3690,8 +3690,8 @@ public final class SatelliteManager { * @param list The list of provisioned satellite subscriber infos. * @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 {@code true}. + * If the request is successful, {@link OutcomeReceiver#onResult} + * will be called. * If the request is not successful, * {@link OutcomeReceiver#onError(Throwable)} will return an error with * a SatelliteException. @@ -3704,7 +3704,7 @@ public final class SatelliteManager { @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS) public void provisionSatellite(@NonNull List<SatelliteSubscriberInfo> list, @NonNull @CallbackExecutor Executor executor, - @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { + @NonNull OutcomeReceiver<Void, SatelliteException> callback) { Objects.requireNonNull(executor); Objects.requireNonNull(callback); @@ -3718,8 +3718,8 @@ public final class SatelliteManager { if (resultData.containsKey(KEY_PROVISION_SATELLITE_TOKENS)) { boolean isUpdated = resultData.getBoolean(KEY_PROVISION_SATELLITE_TOKENS); - executor.execute(() -> Binder.withCleanCallingIdentity(() -> - callback.onResult(isUpdated))); + executor.execute(() -> Binder.withCleanCallingIdentity( + () -> callback.onResult(null))); } else { loge("KEY_REQUEST_PROVISION_TOKENS does not exist."); executor.execute(() -> Binder.withCleanCallingIdentity(() -> @@ -3751,8 +3751,8 @@ public final class SatelliteManager { * @param list The list of deprovisioned satellite subscriber infos. * @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 {@code true}. + * If the request is successful, {@link OutcomeReceiver#onResult} + * will be called. * If the request is not successful, * {@link OutcomeReceiver#onError(Throwable)} will return an error with * a SatelliteException. @@ -3765,7 +3765,7 @@ public final class SatelliteManager { @FlaggedApi(Flags.FLAG_SATELLITE_SYSTEM_APIS) public void deprovisionSatellite(@NonNull List<SatelliteSubscriberInfo> list, @NonNull @CallbackExecutor Executor executor, - @NonNull OutcomeReceiver<Boolean, SatelliteException> callback) { + @NonNull OutcomeReceiver<Void, SatelliteException> callback) { Objects.requireNonNull(executor); Objects.requireNonNull(callback); @@ -3780,7 +3780,7 @@ public final class SatelliteManager { boolean isUpdated = resultData.getBoolean(KEY_DEPROVISION_SATELLITE_TOKENS); executor.execute(() -> Binder.withCleanCallingIdentity(() -> - callback.onResult(isUpdated))); + callback.onResult(null))); } else { loge("KEY_DEPROVISION_SATELLITE_TOKENS does not exist."); executor.execute(() -> Binder.withCleanCallingIdentity(() -> |