summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/bootanimation/BootAnimation.cpp4
-rw-r--r--core/api/current.txt14
-rw-r--r--core/api/module-lib-current.txt24
-rw-r--r--core/api/system-current.txt17
-rw-r--r--core/api/system-lint-baseline.txt4
-rw-r--r--core/api/test-current.txt3
-rw-r--r--core/java/android/app/ApplicationPackageManager.java2
-rw-r--r--core/java/android/app/Notification.java85
-rw-r--r--core/java/android/app/PendingIntent.java18
-rw-r--r--core/java/android/app/WallpaperManager.java26
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java24
-rw-r--r--core/java/android/content/Intent.java22
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/PackageManager.java3
-rw-r--r--core/java/android/content/res/FontScaleConverter.java137
-rw-r--r--core/java/android/content/res/FontScaleConverterFactory.java186
-rw-r--r--core/java/android/content/res/FontScaleConverterImpl.java164
-rw-r--r--core/java/android/content/res/flags.aconfig9
-rw-r--r--core/java/android/hardware/input/InputSettings.java46
-rw-r--r--core/java/android/os/HidlSupport.java7
-rw-r--r--core/java/android/os/HwBinder.java12
-rw-r--r--core/java/android/os/HwNoService.java52
-rw-r--r--core/java/android/os/Process.java2
-rw-r--r--core/java/android/provider/Settings.java15
-rw-r--r--core/java/android/view/WindowManager.java4
-rw-r--r--core/java/android/view/contentcapture/MainContentCaptureSession.java127
-rw-r--r--core/java/android/widget/RemoteViews.java36
-rw-r--r--core/java/android/window/flags/large_screen_experiences_app_compat.aconfig13
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java25
-rw-r--r--core/java/com/android/internal/app/SuspendedAppActivity.java11
-rw-r--r--core/java/com/android/internal/jank/InteractionJankMonitor.java2
-rw-r--r--core/jni/android_os_HidlSupport.cpp8
-rw-r--r--core/jni/android_util_Process.cpp4
-rw-r--r--core/proto/android/providers/settings/secure.proto2
-rw-r--r--core/proto/android/server/windowmanagerservice.proto1
-rw-r--r--core/res/AndroidManifest.xml11
-rw-r--r--core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt59
-rw-r--r--core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt4
-rw-r--r--core/tests/coretests/src/android/widget/RemoteViewsTest.java30
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java169
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt119
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java83
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingConstants.java15
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java26
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java3
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java3
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java4
-rw-r--r--packages/SystemUI/Android.bp1
-rw-r--r--packages/SystemUI/aconfig/systemui.aconfig9
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt2
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepository.kt73
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/notifications/domain/interactor/NotificationSettingsInteractor.kt48
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/notifications/shared/model/NotificationSettingsModel.kt24
-rw-r--r--packages/SystemUI/customization/src/com/android/systemui/shared/settings/data/repository/SecureSettingsRepository.kt102
-rw-r--r--packages/SystemUI/customization/tests/utils/Android.bp33
-rw-r--r--packages/SystemUI/customization/tests/utils/src/com/android/systemui/shared/settings/data/repository/FakeSecureSettingsRepository.kt38
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorInversionRepositoryImplTest.kt140
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapperTest.kt105
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt72
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt89
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/LockscreenTargetFilterTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt)102
-rw-r--r--packages/SystemUI/proguard_common.flags5
-rw-r--r--packages/SystemUI/res/layout/bluetooth_device_item.xml4
-rw-r--r--packages/SystemUI/res/layout/bluetooth_tile_dialog.xml10
-rw-r--r--packages/SystemUI/res/layout/super_notification_shade.xml12
-rw-r--r--packages/SystemUI/res/layout/widget_picker.xml18
-rw-r--r--packages/SystemUI/res/values/config.xml4
-rw-r--r--packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt132
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorInversionRepository.kt73
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt37
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetPickerActivity.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java150
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapper.kt64
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractor.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt54
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/model/ColorInversionTileModel.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt186
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenTargetFilter.kt (renamed from packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenAndDreamTargetFilter.kt)44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt385
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java57
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt43
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt220
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt35
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorInversionRepository.kt39
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/inversion/ColorInversionTileKosmos.kt24
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java6
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java20
-rw-r--r--services/core/java/com/android/server/Watchdog.java1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java3
-rw-r--r--services/core/java/com/android/server/am/OomAdjuster.java10
-rw-r--r--services/core/java/com/android/server/am/OomAdjusterModernImpl.java27
-rw-r--r--services/core/java/com/android/server/am/ProcessErrorStateRecord.java5
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java2
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java28
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java8
-rw-r--r--services/core/java/com/android/server/compat/CompatChange.java3
-rw-r--r--services/core/java/com/android/server/display/AutomaticBrightnessController.java228
-rw-r--r--services/core/java/com/android/server/display/BrightnessMappingStrategy.java175
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java4
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java137
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController2.java122
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerControllerInterface.java5
-rw-r--r--services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java17
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java3
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java7
-rw-r--r--services/core/java/com/android/server/input/InputSettingsObserver.java9
-rw-r--r--services/core/java/com/android/server/input/NativeInputManagerService.java8
-rw-r--r--services/core/java/com/android/server/location/provider/LocationProviderManager.java18
-rw-r--r--services/core/java/com/android/server/notification/flags.aconfig9
-rw-r--r--services/core/java/com/android/server/pm/Computer.java4
-rw-r--r--services/core/java/com/android/server/pm/ComputerEngine.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerInternalBase.java19
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java48
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java5
-rw-r--r--services/core/java/com/android/server/pm/ReconcilePackageUtils.java2
-rw-r--r--services/core/java/com/android/server/pm/Settings.java36
-rw-r--r--services/core/java/com/android/server/pm/SuspendPackageHelper.java160
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java3
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java23
-rw-r--r--services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java3
-rw-r--r--services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java5
-rw-r--r--services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java5
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java3
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartInterceptor.java9
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java15
-rw-r--r--services/core/java/com/android/server/wm/DimmerAnimationHelper.java12
-rw-r--r--services/core/java/com/android/server/wm/TransitionController.java6
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp10
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java4
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java4
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java30
-rw-r--r--services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java17
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java106
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java94
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java61
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java61
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java12
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java61
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt70
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java29
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java17
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java9
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java115
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java8
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java51
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl3
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java18
-rw-r--r--telephony/java/android/telephony/SmsManager.java25
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java3
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java110
-rw-r--r--telephony/java/android/telephony/ims/ImsRegistrationAttributes.java63
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl2
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java215
-rw-r--r--telephony/java/com/android/internal/telephony/ISms.aidl13
-rw-r--r--telephony/java/com/android/internal/telephony/ISmsImplBase.java6
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl14
186 files changed, 5126 insertions, 1815 deletions
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 820d2b0d607e..77b74e9898b8 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -398,8 +398,8 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height,
break;
}
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
diff --git a/core/api/current.txt b/core/api/current.txt
index d1d798346c97..12a6f7459bce 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -13657,6 +13657,16 @@ package android.content.res {
field public int uiMode;
}
+ @FlaggedApi("android.content.res.font_scale_converter_public") public interface FontScaleConverter {
+ method public float convertDpToSp(float);
+ method public float convertSpToDp(float);
+ }
+
+ @FlaggedApi("android.content.res.font_scale_converter_public") public class FontScaleConverterFactory {
+ method @FlaggedApi("android.content.res.font_scale_converter_public") @AnyThread @Nullable public static android.content.res.FontScaleConverter forScale(float);
+ method @FlaggedApi("android.content.res.font_scale_converter_public") @AnyThread public static boolean isNonLinearFontScalingActive(float);
+ }
+
public class ObbInfo implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
@@ -42791,6 +42801,7 @@ package android.telecom {
method @Deprecated @RequiresPermission(android.Manifest.permission.ANSWER_PHONE_CALLS) public boolean endCall();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.net.Uri getAdnUriForPhoneAccount(android.telecom.PhoneAccountHandle);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts();
+ method @FlaggedApi("com.android.internal.telephony.flags.work_profile_api_split") @NonNull @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.INTERACT_ACROSS_PROFILES}) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccountsAcrossProfiles();
method public String getDefaultDialerPackage();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telecom.PhoneAccountHandle getDefaultOutgoingPhoneAccount(String);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.READ_SMS, android.Manifest.permission.READ_PHONE_NUMBERS}, conditional=true) public String getLine1Number(android.telecom.PhoneAccountHandle);
@@ -46612,6 +46623,8 @@ package android.telephony.ims {
method public int getTransportType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int ATTR_EPDG_OVER_CELL_INTERNET = 1; // 0x1
+ field @FlaggedApi("com.android.internal.telephony.flags.emergency_registration_state") public static final int ATTR_REGISTRATION_TYPE_EMERGENCY = 2; // 0x2
+ field @FlaggedApi("com.android.internal.telephony.flags.emergency_registration_state") public static final int ATTR_VIRTUAL_FOR_ANONYMOUS_EMERGENCY_CALL = 4; // 0x4
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsRegistrationAttributes> CREATOR;
}
@@ -53897,6 +53910,7 @@ package android.view {
field public static final String PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH = "android.window.PROPERTY_CAMERA_COMPAT_ALLOW_REFRESH";
field public static final String PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE = "android.window.PROPERTY_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE";
field public static final String PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_DISPLAY_ORIENTATION_OVERRIDE";
+ field @FlaggedApi("com.android.window.flags.app_compat_properties_api") public static final String PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE";
field public static final String PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE = "android.window.PROPERTY_COMPAT_ALLOW_ORIENTATION_OVERRIDE";
field public static final String PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS = "android.window.PROPERTY_COMPAT_ALLOW_SANDBOXING_VIEW_BOUNDS_APIS";
field public static final String PROPERTY_COMPAT_ENABLE_FAKE_FOCUS = "android.window.PROPERTY_COMPAT_ENABLE_FAKE_FOCUS";
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index d395b8cf936e..de330de19560 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -6,7 +6,6 @@ package android {
field public static final String CONTROL_AUTOMOTIVE_GNSS = "android.permission.CONTROL_AUTOMOTIVE_GNSS";
field public static final String GET_INTENT_SENDER_INTENT = "android.permission.GET_INTENT_SENDER_INTENT";
field public static final String MAKE_UID_VISIBLE = "android.permission.MAKE_UID_VISIBLE";
- field @FlaggedApi("android.companion.flags.companion_transport_apis") public static final String USE_COMPANION_TRANSPORTS = "android.permission.USE_COMPANION_TRANSPORTS";
}
}
@@ -82,29 +81,6 @@ package android.app.admin {
}
-package android.companion {
-
- public final class CompanionDeviceManager {
- method @FlaggedApi("android.companion.companion_transport_apis") @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void addOnMessageReceivedListener(@NonNull java.util.concurrent.Executor, int, @NonNull android.companion.CompanionDeviceManager.OnMessageReceivedListener);
- method @FlaggedApi("android.companion.companion_transport_apis") @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void addOnTransportsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.OnTransportsChangedListener);
- method @FlaggedApi("android.companion.companion_transport_apis") @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void removeOnMessageReceivedListener(int, @NonNull android.companion.CompanionDeviceManager.OnMessageReceivedListener);
- method @FlaggedApi("android.companion.companion_transport_apis") @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void removeOnTransportsChangedListener(@NonNull android.companion.CompanionDeviceManager.OnTransportsChangedListener);
- method @FlaggedApi("android.companion.companion_transport_apis") @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void sendMessage(int, @NonNull byte[], @NonNull int[]);
- field @FlaggedApi("android.companion.companion_transport_apis") public static final int MESSAGE_REQUEST_CONTEXT_SYNC = 1667729539; // 0x63678883
- field @FlaggedApi("android.companion.companion_transport_apis") public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 1669491075; // 0x63826983
- field @FlaggedApi("android.companion.companion_transport_apis") public static final int MESSAGE_REQUEST_REMOTE_AUTHENTICATION = 1669494629; // 0x63827765
- }
-
- @FlaggedApi("android.companion.companion_transport_apis") public static interface CompanionDeviceManager.OnMessageReceivedListener {
- method public void onMessageReceived(int, @NonNull byte[]);
- }
-
- @FlaggedApi("android.companion.companion_transport_apis") public static interface CompanionDeviceManager.OnTransportsChangedListener {
- method public void onTransportsChanged(@NonNull java.util.List<android.companion.AssociationInfo>);
- }
-
-}
-
package android.content {
public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index fc0fb35b233d..8ce3a8dfb5a2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -158,6 +158,7 @@ package android {
field public static final String INTERACT_ACROSS_USERS_FULL = "android.permission.INTERACT_ACROSS_USERS_FULL";
field public static final String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
field public static final String INVOKE_CARRIER_SETUP = "android.permission.INVOKE_CARRIER_SETUP";
+ field public static final String KEYPHRASE_ENROLLMENT_APPLICATION = "android.permission.KEYPHRASE_ENROLLMENT_APPLICATION";
field public static final String KILL_ALL_BACKGROUND_PROCESSES = "android.permission.KILL_ALL_BACKGROUND_PROCESSES";
field public static final String KILL_UID = "android.permission.KILL_UID";
field public static final String LAUNCH_DEVICE_MANAGER_SETUP = "android.permission.LAUNCH_DEVICE_MANAGER_SETUP";
@@ -214,6 +215,7 @@ package android {
field public static final String MANAGE_USB = "android.permission.MANAGE_USB";
field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS";
field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE";
+ field public static final String MANAGE_VOICE_KEYPHRASES = "android.permission.MANAGE_VOICE_KEYPHRASES";
field public static final String MANAGE_WALLPAPER_EFFECTS_GENERATION = "android.permission.MANAGE_WALLPAPER_EFFECTS_GENERATION";
field public static final String MANAGE_WEAK_ESCROW_TOKEN = "android.permission.MANAGE_WEAK_ESCROW_TOKEN";
field public static final String MANAGE_WEARABLE_SENSING_SERVICE = "android.permission.MANAGE_WEARABLE_SENSING_SERVICE";
@@ -8987,9 +8989,9 @@ package android.media.tv.tuner.frontend {
package android.media.voice {
public final class KeyphraseModelManager {
- method @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public void deleteKeyphraseSoundModel(int, @NonNull java.util.Locale);
- method @Nullable @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel getKeyphraseSoundModel(int, @NonNull java.util.Locale);
- method @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public void updateKeyphraseSoundModel(@NonNull android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_VOICE_KEYPHRASES) public void deleteKeyphraseSoundModel(int, @NonNull java.util.Locale);
+ method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_VOICE_KEYPHRASES) public android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel getKeyphraseSoundModel(int, @NonNull java.util.Locale);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_VOICE_KEYPHRASES) public void updateKeyphraseSoundModel(@NonNull android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel);
}
}
@@ -13051,7 +13053,7 @@ package android.service.voice {
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(@NonNull String, @NonNull java.util.Locale, @Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.AlwaysOnHotwordDetector.Callback);
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull android.service.voice.HotwordDetector.Callback);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.HotwordDetector createHotwordDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.HotwordDetector.Callback);
- method @NonNull @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_VOICE_KEYPHRASES) public final android.media.voice.KeyphraseModelManager createKeyphraseModelManager();
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public final android.service.voice.VisualQueryDetector createVisualQueryDetector(@Nullable android.os.PersistableBundle, @Nullable android.os.SharedMemory, @NonNull java.util.concurrent.Executor, @NonNull android.service.voice.VisualQueryDetector.Callback);
method @FlaggedApi("android.service.voice.flags.allow_training_data_egress_from_hds") @RequiresPermission(android.Manifest.permission.MANAGE_HOTWORD_DETECTION) public void setShouldReceiveSandboxedTrainingData(boolean);
}
@@ -13514,6 +13516,7 @@ package android.telecom {
method public java.util.List<android.telecom.PhoneAccount> getAllPhoneAccounts();
method public int getAllPhoneAccountsCount();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccounts(boolean);
+ method @FlaggedApi("com.android.internal.telephony.flags.work_profile_api_split") @NonNull @RequiresPermission(allOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.INTERACT_ACROSS_PROFILES}) public java.util.List<android.telecom.PhoneAccountHandle> getCallCapablePhoneAccountsAcrossProfiles(boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}, conditional=true) public int getCallState();
method public android.telecom.PhoneAccountHandle getConnectionManager();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode();
@@ -15723,6 +15726,7 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(int, int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(int, int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException;
+ method @FlaggedApi("com.android.internal.telephony.flags.emergency_registration_state") public void registerImsEmergencyRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCrossSimCallingEnabled(boolean) throws android.telephony.ims.ImsException;
@@ -15733,6 +15737,7 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingSettingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean);
+ method @FlaggedApi("com.android.internal.telephony.flags.emergency_registration_state") public void unregisterImsEmergencyRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback);
}
@@ -15765,6 +15770,8 @@ package android.telephony.ims {
ctor public ImsRegistrationAttributes.Builder(int);
method @NonNull public android.telephony.ims.ImsRegistrationAttributes build();
method @NonNull public android.telephony.ims.ImsRegistrationAttributes.Builder setFeatureTags(@NonNull java.util.Set<java.lang.String>);
+ method @FlaggedApi("com.android.internal.telephony.flags.emergency_registration_state") @NonNull public android.telephony.ims.ImsRegistrationAttributes.Builder setFlagRegistrationTypeEmergency();
+ method @FlaggedApi("com.android.internal.telephony.flags.emergency_registration_state") @NonNull public android.telephony.ims.ImsRegistrationAttributes.Builder setFlagVirtualRegistrationForEmergencyCall();
method @NonNull public android.telephony.ims.ImsRegistrationAttributes.Builder setSipDetails(@NonNull android.telephony.ims.SipDetails);
}
@@ -16691,6 +16698,7 @@ package android.telephony.ims.stub {
ctor public ImsRegistrationImplBase(@NonNull java.util.concurrent.Executor);
method public final void onDeregistered(android.telephony.ims.ImsReasonInfo);
method public final void onDeregistered(@Nullable android.telephony.ims.ImsReasonInfo, int, int);
+ method @FlaggedApi("com.android.internal.telephony.flags.emergency_registration_state") public final void onDeregistered(@Nullable android.telephony.ims.ImsReasonInfo, int, @NonNull android.telephony.ims.ImsRegistrationAttributes);
method public final void onDeregistered(@Nullable android.telephony.ims.ImsReasonInfo, @NonNull android.telephony.ims.SipDetails);
method public final void onDeregistered(@Nullable android.telephony.ims.ImsReasonInfo, int, int, @NonNull android.telephony.ims.SipDetails);
method public final void onRegistered(int);
@@ -16699,6 +16707,7 @@ package android.telephony.ims.stub {
method public final void onRegistering(@NonNull android.telephony.ims.ImsRegistrationAttributes);
method public final void onSubscriberAssociatedUriChanged(android.net.Uri[]);
method public final void onTechnologyChangeFailed(int, android.telephony.ims.ImsReasonInfo);
+ method @FlaggedApi("com.android.internal.telephony.flags.emergency_registration_state") public final void onTechnologyChangeFailed(@Nullable android.telephony.ims.ImsReasonInfo, @NonNull android.telephony.ims.ImsRegistrationAttributes);
method public void triggerFullNetworkRegistration(@IntRange(from=100, to=699) int, @Nullable String);
method public void triggerSipDelegateDeregistration();
method public void updateSipDelegateRegistration();
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index cef11bb42c3f..b2a28b2127bc 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -1995,8 +1995,12 @@ UnflaggedApi: android.Manifest.permission#ALWAYS_UPDATE_WALLPAPER:
New API must be flagged with @FlaggedApi: field android.Manifest.permission.ALWAYS_UPDATE_WALLPAPER
UnflaggedApi: android.Manifest.permission#CAMERA_HEADLESS_SYSTEM_USER:
New API must be flagged with @FlaggedApi: field android.Manifest.permission.CAMERA_HEADLESS_SYSTEM_USER
+UnflaggedApi: android.Manifest.permission#KEYPHRASE_ENROLLMENT_APPLICATION:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.KEYPHRASE_ENROLLMENT_APPLICATION
UnflaggedApi: android.Manifest.permission#LAUNCH_PERMISSION_SETTINGS:
New API must be flagged with @FlaggedApi: field android.Manifest.permission.LAUNCH_PERMISSION_SETTINGS
+UnflaggedApi: android.Manifest.permission#MANAGE_VOICE_KEYPHRASES:
+ New API must be flagged with @FlaggedApi: field android.Manifest.permission.MANAGE_VOICE_KEYPHRASES
UnflaggedApi: android.Manifest.permission#READ_INSTALLED_SESSION_PATHS:
New API must be flagged with @FlaggedApi: field android.Manifest.permission.READ_INSTALLED_SESSION_PATHS
UnflaggedApi: android.Manifest.permission#REGISTER_NSD_OFFLOAD_ENGINE:
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index a3cd3dc87db3..42daea24593e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -882,7 +882,6 @@ package android.companion {
public final class CompanionDeviceManager {
method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public void enableSecureTransport(boolean);
- field @FlaggedApi("android.companion.companion_transport_apis") public static final int MESSAGE_REQUEST_PING = 1669362552; // 0x63807378
}
public abstract class CompanionDeviceService extends android.app.Service {
@@ -2133,7 +2132,7 @@ package android.media.tv.tuner {
package android.media.voice {
public final class KeyphraseModelManager {
- method @RequiresPermission("android.permission.MANAGE_VOICE_KEYPHRASES") public void setModelDatabaseForTestEnabled(boolean);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_VOICE_KEYPHRASES) public void setModelDatabaseForTestEnabled(boolean);
}
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 287d2bd9e6a7..87c86df6140d 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2909,7 +2909,7 @@ public class ApplicationPackageManager extends PackageManager {
try {
return mPM.setPackagesSuspendedAsUser(packageNames, suspended, appExtras,
launcherExtras, dialogInfo, flags, mContext.getOpPackageName(),
- UserHandle.myUserId() /* suspendingUserId */, getUserId() /* targetUserId */);
+ getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 013bcddbb7f3..a510c7704751 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2205,6 +2205,9 @@ public class Notification implements Parcelable
private void visitUris(@NonNull Consumer<Uri> visitor) {
visitIconUri(visitor, getIcon());
+ if (actionIntent != null) {
+ actionIntent.visitUris(visitor);
+ }
}
@Override
@@ -2898,6 +2901,21 @@ public class Notification implements Parcelable
}
}
+ // allPendingIntents should contain all associated intents after parcelling, but it may also
+ // contain intents added by the app to extras for their own purposes. We only care about
+ // checking the intents known and used by system_server, to avoid the confused deputy issue.
+ List<PendingIntent> pendingIntents = Arrays.asList(contentIntent, deleteIntent,
+ fullScreenIntent);
+ for (PendingIntent intent : pendingIntents) {
+ if (intent != null) {
+ intent.visitUris(visitor);
+ }
+ }
+
+ if (mBubbleMetadata != null) {
+ mBubbleMetadata.visitUris(visitor);
+ }
+
if (extras != null) {
visitIconUri(visitor, extras.getParcelable(EXTRA_LARGE_ICON_BIG, Icon.class));
visitIconUri(visitor, extras.getParcelable(EXTRA_PICTURE_ICON, Icon.class));
@@ -2969,15 +2987,28 @@ public class Notification implements Parcelable
callPerson.visitUris(visitor);
}
visitIconUri(visitor, extras.getParcelable(EXTRA_VERIFICATION_ICON, Icon.class));
- }
- if (mBubbleMetadata != null) {
- visitIconUri(visitor, mBubbleMetadata.getIcon());
- }
+ // Extras for MediaStyle.
+ PendingIntent deviceIntent = extras.getParcelable(EXTRA_MEDIA_REMOTE_INTENT,
+ PendingIntent.class);
+ if (deviceIntent != null) {
+ deviceIntent.visitUris(visitor);
+ }
- if (extras != null && extras.containsKey(WearableExtender.EXTRA_WEARABLE_EXTENSIONS)) {
- WearableExtender extender = new WearableExtender(this);
- extender.visitUris(visitor);
+ if (extras.containsKey(WearableExtender.EXTRA_WEARABLE_EXTENSIONS)) {
+ WearableExtender extender = new WearableExtender(this);
+ extender.visitUris(visitor);
+ }
+
+ if (extras.containsKey(TvExtender.EXTRA_TV_EXTENDER)) {
+ TvExtender extender = new TvExtender(this);
+ extender.visitUris(visitor);
+ }
+
+ if (extras.containsKey(CarExtender.EXTRA_CAR_EXTENDER)) {
+ CarExtender extender = new CarExtender(this);
+ extender.visitUris(visitor);
+ }
}
}
@@ -10558,6 +10589,16 @@ public class Notification implements Parcelable
}
}
+ private void visitUris(@NonNull Consumer<Uri> visitor) {
+ visitIconUri(visitor, getIcon());
+ if (mPendingIntent != null) {
+ mPendingIntent.visitUris(visitor);
+ }
+ if (mDeleteIntent != null) {
+ mDeleteIntent.visitUris(visitor);
+ }
+ }
+
/**
* Builder to construct a {@link BubbleMetadata} object.
*/
@@ -11756,6 +11797,9 @@ public class Notification implements Parcelable
}
private void visitUris(@NonNull Consumer<Uri> visitor) {
+ if (mDisplayIntent != null) {
+ mDisplayIntent.visitUris(visitor);
+ }
for (Action action : mActions) {
action.visitUris(visitor);
}
@@ -11908,12 +11952,19 @@ public class Notification implements Parcelable
/**
* Returns the unread conversation conveyed by this notification.
+ *
* @see #setUnreadConversation(UnreadConversation)
*/
public UnreadConversation getUnreadConversation() {
return mUnreadConversation;
}
+ private void visitUris(@NonNull Consumer<Uri> visitor) {
+ if (mUnreadConversation != null) {
+ mUnreadConversation.visitUris(visitor);
+ }
+ }
+
/**
* A class which holds the unread messages from a conversation.
*/
@@ -12065,7 +12116,16 @@ public class Notification implements Parcelable
onRead,
participants, b.getLong(KEY_TIMESTAMP));
}
- };
+
+ private void visitUris(@NonNull Consumer<Uri> visitor) {
+ if (mReadPendingIntent != null) {
+ mReadPendingIntent.visitUris(visitor);
+ }
+ if (mReplyPendingIntent != null) {
+ mReplyPendingIntent.visitUris(visitor);
+ }
+ }
+ }
/**
* Builder class for {@link CarExtender.UnreadConversation} objects.
@@ -12388,6 +12448,15 @@ public class Notification implements Parcelable
public boolean isSuppressShowOverApps() {
return mSuppressShowOverApps;
}
+
+ private void visitUris(@NonNull Consumer<Uri> visitor) {
+ if (mContentIntent != null) {
+ mContentIntent.visitUris(visitor);
+ }
+ if (mDeleteIntent != null) {
+ mDeleteIntent.visitUris(visitor);
+ }
+ }
}
/**
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 62209b0fd27d..0261f0a02174 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -44,6 +44,8 @@ import android.content.IntentSender;
import android.content.pm.PackageManager.ResolveInfoFlagsBits;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -69,6 +71,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* A description of an Intent and target action to perform with it. Instances
@@ -1460,6 +1463,21 @@ public final class PendingIntent implements Parcelable {
return sb.toString();
}
+ /**
+ * See {@link Intent#visitUris(Consumer)}.
+ *
+ * @hide
+ */
+ public void visitUris(@NonNull Consumer<Uri> visitor) {
+ if (android.app.Flags.visitRiskyUris()) {
+ Intent intent = Binder.withCleanCallingIdentity(this::getIntent);
+
+ if (intent != null) {
+ intent.visitUris(visitor);
+ }
+ }
+ }
+
/** @hide */
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 820ff3e308e4..be420debc88f 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -77,6 +77,7 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.StrictMode;
import android.os.SystemProperties;
+import android.os.Trace;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -91,7 +92,6 @@ import com.android.internal.R;
import libcore.io.IoUtils;
import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -614,11 +614,14 @@ public class WallpaperManager {
ColorManagementProxy cmProxy) {
if (mService != null) {
try {
+ Trace.beginSection("WPMS.isWallpaperSupported");
if (!mService.isWallpaperSupported(context.getOpPackageName())) {
return null;
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
+ } finally {
+ Trace.endSection();
}
}
synchronized (this) {
@@ -629,6 +632,7 @@ public class WallpaperManager {
mCachedWallpaper = null;
Bitmap currentWallpaper = null;
try {
+ Trace.beginSection("WPMS.getCurrentWallpaperLocked");
currentWallpaper = getCurrentWallpaperLocked(
context, which, userId, hardware, cmProxy);
} catch (OutOfMemoryError e) {
@@ -654,6 +658,8 @@ public class WallpaperManager {
// Post-O apps really most sincerely need the permission.
throw e;
}
+ } finally {
+ Trace.endSection();
}
if (currentWallpaper != null) {
mCachedWallpaper = new CachedWallpaper(currentWallpaper, userId, which);
@@ -732,19 +738,15 @@ public class WallpaperManager {
try {
Bundle params = new Bundle();
+ Trace.beginSection("WPMS.getWallpaperWithFeature_" + which);
ParcelFileDescriptor pfd = mService.getWallpaperWithFeature(
context.getOpPackageName(), context.getAttributionTag(), this, which,
params, userId, /* getCropped = */ true);
+ Trace.endSection();
if (pfd != null) {
- try (BufferedInputStream bis = new BufferedInputStream(
- new ParcelFileDescriptor.AutoCloseInputStream(pfd))) {
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int data;
- while ((data = bis.read()) != -1) {
- baos.write(data);
- }
- ImageDecoder.Source src = ImageDecoder.createSource(baos.toByteArray());
+ try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+ ImageDecoder.Source src = ImageDecoder.createSource(is.readAllBytes());
return ImageDecoder.decodeBitmap(src, ((decoder, info, source) -> {
// Mutable and hardware config can't be set at the same time.
decoder.setMutableRequired(!hardware);
@@ -764,13 +766,18 @@ public class WallpaperManager {
}
private Bitmap getDefaultWallpaper(Context context, @SetWallpaperFlags int which) {
+ Trace.beginSection("WPMS.getDefaultWallpaper_" + which);
Bitmap defaultWallpaper = mDefaultWallpaper;
if (defaultWallpaper == null || defaultWallpaper.isRecycled()) {
defaultWallpaper = null;
+ Trace.beginSection("WPMS.openDefaultWallpaper");
try (InputStream is = openDefaultWallpaper(context, which)) {
+ Trace.endSection();
if (is != null) {
BitmapFactory.Options options = new BitmapFactory.Options();
+ Trace.beginSection("WPMS.decodeStream");
defaultWallpaper = BitmapFactory.decodeStream(is, null, options);
+ Trace.endSection();
}
} catch (OutOfMemoryError | IOException e) {
Log.w(TAG, "Can't decode stream", e);
@@ -779,6 +786,7 @@ public class WallpaperManager {
synchronized (this) {
mDefaultWallpaper = defaultWallpaper;
}
+ Trace.endSection();
return defaultWallpaper;
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index d5b5f40a6980..b11840e8a931 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -20,7 +20,6 @@ import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMIN
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION;
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER;
import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH;
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
import android.annotation.CallbackExecutor;
import android.annotation.FlaggedApi;
@@ -219,31 +218,24 @@ public final class CompanionDeviceManager {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @TestApi public static final int MESSAGE_REQUEST_PING = 0x63807378; // ?PIN
+ public static final int MESSAGE_REQUEST_PING = 0x63807378; // ?PIN
/**
* Message header assigned to the remote authentication handshakes.
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @SystemApi(client = MODULE_LIBRARIES)
public static final int MESSAGE_REQUEST_REMOTE_AUTHENTICATION = 0x63827765; // ?RMA
/**
* Message header assigned to the telecom context sync metadata.
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @SystemApi(client = MODULE_LIBRARIES)
public static final int MESSAGE_REQUEST_CONTEXT_SYNC = 0x63678883; // ?CXS
/**
* Message header assigned to the permission restore request.
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @SystemApi(client = MODULE_LIBRARIES)
public static final int MESSAGE_REQUEST_PERMISSION_RESTORE = 0x63826983; // ?RES
/**
@@ -905,8 +897,6 @@ public final class CompanionDeviceManager {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @SystemApi(client = MODULE_LIBRARIES)
public interface OnTransportsChangedListener {
/**
* Invoked when a transport is attached or detached.
@@ -925,8 +915,6 @@ public final class CompanionDeviceManager {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void addOnTransportsChangedListener(
@NonNull @CallbackExecutor Executor executor,
@@ -947,8 +935,6 @@ public final class CompanionDeviceManager {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void removeOnTransportsChangedListener(
@NonNull OnTransportsChangedListener listener) {
@@ -969,8 +955,6 @@ public final class CompanionDeviceManager {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void sendMessage(int messageType, @NonNull byte[] data, @NonNull int[] associationIds) {
try {
@@ -987,8 +971,6 @@ public final class CompanionDeviceManager {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @SystemApi(client = MODULE_LIBRARIES)
public interface OnMessageReceivedListener {
/**
* Called when a message is received.
@@ -1001,8 +983,6 @@ public final class CompanionDeviceManager {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void addOnMessageReceivedListener(
@NonNull @CallbackExecutor Executor executor, int messageType,
@@ -1021,8 +1001,6 @@ public final class CompanionDeviceManager {
*
* @hide
*/
- @FlaggedApi(Flags.FLAG_COMPANION_TRANSPORT_APIS)
- @SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS)
public void removeOnMessageReceivedListener(int messageType,
@NonNull OnMessageReceivedListener listener) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7af0be3b3e75..183b9b0000d2 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -101,6 +101,7 @@ import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
+import java.util.function.Consumer;
/**
* An intent is an abstract description of an operation to be performed. It
@@ -8147,6 +8148,27 @@ public class Intent implements Parcelable, Cloneable {
}
}
+ /**
+ * Note all {@link Uri} that are referenced internally, with the expectation that Uri permission
+ * grants will need to be issued to ensure the recipient of this object is able to render its
+ * contents.
+ * See b/281044385 for more context and examples about what happens when this isn't done
+ * correctly.
+ *
+ * @hide
+ */
+ public void visitUris(@NonNull Consumer<Uri> visitor) {
+ if (android.app.Flags.visitRiskyUris()) {
+ visitor.accept(mData);
+ if (mSelector != null) {
+ mSelector.visitUris(visitor);
+ }
+ if (mOriginalIntent != null) {
+ mOriginalIntent.visitUris(visitor);
+ }
+ }
+ }
+
public static Intent getIntentOld(String uri) throws URISyntaxException {
Intent intent = getIntentOld(uri, 0);
intent.mLocalFlags |= LOCAL_FLAG_FROM_URI;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 6dc8d4738c87..98623de810c4 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -300,8 +300,7 @@ interface IPackageManager {
String[] setPackagesSuspendedAsUser(in String[] packageNames, boolean suspended,
in PersistableBundle appExtras, in PersistableBundle launcherExtras,
- in SuspendDialogInfo dialogInfo, int flags, String suspendingPackage,
- int suspendingUserId, int targetUserId);
+ in SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId);
String[] getUnsuspendablePackagesForUser(in String[] packageNames, int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a8638708824b..82a8c11f024f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -10000,9 +10000,6 @@ public abstract class PackageManager {
* device administrators or apps holding {@link android.Manifest.permission#MANAGE_USERS} or
* {@link android.Manifest.permission#SUSPEND_APPS}.
*
- * <p>
- * <strong>Note:</strong>This API doesn't support cross user suspension and should only be used
- * for testing.
* @param suspendedPackage The package that has been suspended.
* @return Name of the package that suspended the given package. Returns {@code null} if the
* given package is not currently suspended and the platform package name - i.e.
diff --git a/core/java/android/content/res/FontScaleConverter.java b/core/java/android/content/res/FontScaleConverter.java
index 28525e25bdd7..088949e7eec2 100644
--- a/core/java/android/content/res/FontScaleConverter.java
+++ b/core/java/android/content/res/FontScaleConverter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,15 +16,11 @@
package android.content.res;
-import android.annotation.NonNull;
-import android.util.MathUtils;
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Arrays;
+import android.annotation.FlaggedApi;
/**
- * A lookup table for non-linear font scaling. Converts font sizes given in "sp" dimensions to a
+ * A converter for non-linear font scaling. Converts font sizes given in "sp" dimensions to a
* "dp" dimension according to a non-linear curve.
*
* <p>This is meant to improve readability at larger font scales: larger fonts will scale up more
@@ -32,131 +28,16 @@ import java.util.Arrays;
*
* <p>The thinking here is that large fonts are already big enough to read, but we still want to
* scale them slightly to preserve the visual hierarchy when compared to smaller fonts.
- *
- * @hide
*/
-public class FontScaleConverter {
-
- @VisibleForTesting
- final float[] mFromSpValues;
- @VisibleForTesting
- final float[] mToDpValues;
-
+@FlaggedApi(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC)
+public interface FontScaleConverter {
/**
- * Creates a lookup table for the given conversions.
- *
- * <p>Any "sp" value not in the lookup table will be derived via linear interpolation.
- *
- * <p>The arrays must be sorted ascending and monotonically increasing.
- *
- * @param fromSp array of dimensions in SP
- * @param toDp array of dimensions in DP that correspond to an SP value in fromSp
- *
- * @throws IllegalArgumentException if the array lengths don't match or are empty
- * @hide
+ * Converts a dimension in "sp" to "dp".
*/
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public FontScaleConverter(@NonNull float[] fromSp, @NonNull float[] toDp) {
- if (fromSp.length != toDp.length || fromSp.length == 0) {
- throw new IllegalArgumentException("Array lengths must match and be nonzero");
- }
-
- mFromSpValues = fromSp;
- mToDpValues = toDp;
- }
+ float convertSpToDp(float sp);
/**
- * Convert a dimension in "dp" back to "sp" using the lookup table.
- *
- * @hide
+ * Converts a dimension in "dp" back to "sp".
*/
- public float convertDpToSp(float dp) {
- return lookupAndInterpolate(dp, mToDpValues, mFromSpValues);
- }
-
- /**
- * Convert a dimension in "sp" to "dp" using the lookup table.
- *
- * @hide
- */
- public float convertSpToDp(float sp) {
- return lookupAndInterpolate(sp, mFromSpValues, mToDpValues);
- }
-
- private static float lookupAndInterpolate(
- float sourceValue,
- float[] sourceValues,
- float[] targetValues
- ) {
- final float sourceValuePositive = Math.abs(sourceValue);
- // TODO(b/247861374): find a match at a higher index?
- final float sign = Math.signum(sourceValue);
- // We search for exact matches only, even if it's just a little off. The interpolation will
- // handle any non-exact matches.
- final int index = Arrays.binarySearch(sourceValues, sourceValuePositive);
- if (index >= 0) {
- // exact match, return the matching dp
- return sign * targetValues[index];
- } else {
- // must be a value in between index and index + 1: interpolate.
- final int lowerIndex = -(index + 1) - 1;
-
- final float startSp;
- final float endSp;
- final float startDp;
- final float endDp;
-
- if (lowerIndex >= sourceValues.length - 1) {
- // It's past our lookup table. Determine the last elements' scaling factor and use.
- startSp = sourceValues[sourceValues.length - 1];
- startDp = targetValues[sourceValues.length - 1];
-
- if (startSp == 0) return 0;
-
- final float scalingFactor = startDp / startSp;
- return sourceValue * scalingFactor;
- } else if (lowerIndex == -1) {
- // It's smaller than the smallest value in our table. Interpolate from 0.
- startSp = 0;
- startDp = 0;
- endSp = sourceValues[0];
- endDp = targetValues[0];
- } else {
- startSp = sourceValues[lowerIndex];
- endSp = sourceValues[lowerIndex + 1];
- startDp = targetValues[lowerIndex];
- endDp = targetValues[lowerIndex + 1];
- }
-
- return sign
- * MathUtils.constrainedMap(startDp, endDp, startSp, endSp, sourceValuePositive);
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null) return false;
- if (!(o instanceof FontScaleConverter)) return false;
- FontScaleConverter that = (FontScaleConverter) o;
- return Arrays.equals(mFromSpValues, that.mFromSpValues)
- && Arrays.equals(mToDpValues, that.mToDpValues);
- }
-
- @Override
- public int hashCode() {
- int result = Arrays.hashCode(mFromSpValues);
- result = 31 * result + Arrays.hashCode(mToDpValues);
- return result;
- }
-
- @Override
- public String toString() {
- return "FontScaleConverter{"
- + "fromSpValues="
- + Arrays.toString(mFromSpValues)
- + ", toDpValues="
- + Arrays.toString(mToDpValues)
- + '}';
- }
+ float convertDpToSp(float dp);
}
diff --git a/core/java/android/content/res/FontScaleConverterFactory.java b/core/java/android/content/res/FontScaleConverterFactory.java
index 5eb65262918d..5d31cc0f0243 100644
--- a/core/java/android/content/res/FontScaleConverterFactory.java
+++ b/core/java/android/content/res/FontScaleConverterFactory.java
@@ -16,6 +16,8 @@
package android.content.res;
+import android.annotation.AnyThread;
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.MathUtils;
@@ -24,67 +26,88 @@ import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
/**
- * Stores lookup tables for creating {@link FontScaleConverter}s at various scales.
+ * Creates {@link FontScaleConverter}s at various scales.
*
- * @hide
+ * Generally you shouldn't need this; you can use {@link
+ * android.util.TypedValue#applyDimension(int, float, DisplayMetrics)} directly and it will do the
+ * scaling conversion for you. But for UI frameworks or other situations where you need to do the
+ * conversion without an Android Context, you can use this class.
*/
+@FlaggedApi(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC)
public class FontScaleConverterFactory {
private static final float SCALE_KEY_MULTIPLIER = 100f;
+ /** @hide */
+ // GuardedBy("LOOKUP_TABLES_WRITE_LOCK") but only for writes!
@VisibleForTesting
- static final SparseArray<FontScaleConverter> LOOKUP_TABLES = new SparseArray<>();
+ @NonNull
+ public static volatile SparseArray<FontScaleConverter> sLookupTables = new SparseArray<>();
+
+ /**
+ * This is a write lock only! We don't care about synchronization on reads; they can be a bit
+ * out of date. But all writes have to be atomic, so we use this similar to a
+ * CopyOnWriteArrayList.
+ */
+ private static final Object LOOKUP_TABLES_WRITE_LOCK = new Object();
private static float sMinScaleBeforeCurvesApplied = 1.05f;
static {
// These were generated by frameworks/base/tools/fonts/font-scaling-array-generator.js and
// manually tweaked for optimum readability.
- put(
- /* scaleKey= */ 1.15f,
- new FontScaleConverter(
- /* fromSp= */
- new float[] { 8f, 10f, 12f, 14f, 18f, 20f, 24f, 30f, 100},
- /* toDp= */
- new float[] { 9.2f, 11.5f, 13.8f, 16.4f, 19.8f, 21.8f, 25.2f, 30f, 100})
- );
-
- put(
- /* scaleKey= */ 1.3f,
- new FontScaleConverter(
- /* fromSp= */
- new float[] { 8f, 10f, 12f, 14f, 18f, 20f, 24f, 30f, 100},
- /* toDp= */
- new float[] {10.4f, 13f, 15.6f, 18.8f, 21.6f, 23.6f, 26.4f, 30f, 100})
- );
-
- put(
- /* scaleKey= */ 1.5f,
- new FontScaleConverter(
- /* fromSp= */
- new float[] { 8f, 10f, 12f, 14f, 18f, 20f, 24f, 30f, 100},
- /* toDp= */
- new float[] { 12f, 15f, 18f, 22f, 24f, 26f, 28f, 30f, 100})
- );
-
- put(
- /* scaleKey= */ 1.8f,
- new FontScaleConverter(
- /* fromSp= */
- new float[] { 8f, 10f, 12f, 14f, 18f, 20f, 24f, 30f, 100},
- /* toDp= */
- new float[] {14.4f, 18f, 21.6f, 24.4f, 27.6f, 30.8f, 32.8f, 34.8f, 100})
- );
-
- put(
- /* scaleKey= */ 2f,
- new FontScaleConverter(
- /* fromSp= */
- new float[] { 8f, 10f, 12f, 14f, 18f, 20f, 24f, 30f, 100},
- /* toDp= */
- new float[] { 16f, 20f, 24f, 26f, 30f, 34f, 36f, 38f, 100})
- );
-
- sMinScaleBeforeCurvesApplied = getScaleFromKey(LOOKUP_TABLES.keyAt(0)) - 0.02f;
+ synchronized (LOOKUP_TABLES_WRITE_LOCK) {
+ putInto(
+ sLookupTables,
+ /* scaleKey= */ 1.15f,
+ new FontScaleConverterImpl(
+ /* fromSp= */
+ new float[] { 8f, 10f, 12f, 14f, 18f, 20f, 24f, 30f, 100},
+ /* toDp= */
+ new float[] { 9.2f, 11.5f, 13.8f, 16.4f, 19.8f, 21.8f, 25.2f, 30f, 100})
+ );
+
+ putInto(
+ sLookupTables,
+ /* scaleKey= */ 1.3f,
+ new FontScaleConverterImpl(
+ /* fromSp= */
+ new float[] { 8f, 10f, 12f, 14f, 18f, 20f, 24f, 30f, 100},
+ /* toDp= */
+ new float[] {10.4f, 13f, 15.6f, 18.8f, 21.6f, 23.6f, 26.4f, 30f, 100})
+ );
+
+ putInto(
+ sLookupTables,
+ /* scaleKey= */ 1.5f,
+ new FontScaleConverterImpl(
+ /* fromSp= */
+ new float[] { 8f, 10f, 12f, 14f, 18f, 20f, 24f, 30f, 100},
+ /* toDp= */
+ new float[] { 12f, 15f, 18f, 22f, 24f, 26f, 28f, 30f, 100})
+ );
+
+ putInto(
+ sLookupTables,
+ /* scaleKey= */ 1.8f,
+ new FontScaleConverterImpl(
+ /* fromSp= */
+ new float[] { 8f, 10f, 12f, 14f, 18f, 20f, 24f, 30f, 100},
+ /* toDp= */
+ new float[] {14.4f, 18f, 21.6f, 24.4f, 27.6f, 30.8f, 32.8f, 34.8f, 100})
+ );
+
+ putInto(
+ sLookupTables,
+ /* scaleKey= */ 2f,
+ new FontScaleConverterImpl(
+ /* fromSp= */
+ new float[] { 8f, 10f, 12f, 14f, 18f, 20f, 24f, 30f, 100},
+ /* toDp= */
+ new float[] { 16f, 20f, 24f, 26f, 30f, 34f, 36f, 38f, 100})
+ );
+ }
+
+ sMinScaleBeforeCurvesApplied = getScaleFromKey(sLookupTables.keyAt(0)) - 0.02f;
if (sMinScaleBeforeCurvesApplied <= 1.0f) {
throw new IllegalStateException(
"You should only apply non-linear scaling to font scales > 1"
@@ -100,9 +123,9 @@ public class FontScaleConverterFactory {
*
* <p>Example usage:
* <code>isNonLinearFontScalingActive(getResources().getConfiguration().fontScale)</code>
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC)
+ @AnyThread
public static boolean isNonLinearFontScalingActive(float fontScale) {
return fontScale >= sMinScaleBeforeCurvesApplied;
}
@@ -113,10 +136,10 @@ public class FontScaleConverterFactory {
* @param fontScale the scale factor, usually from {@link Configuration#fontScale}.
*
* @return a converter for the given scale, or null if non-linear scaling should not be used.
- *
- * @hide
*/
+ @FlaggedApi(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC)
@Nullable
+ @AnyThread
public static FontScaleConverter forScale(float fontScale) {
if (!isNonLinearFontScalingActive(fontScale)) {
return null;
@@ -128,23 +151,33 @@ public class FontScaleConverterFactory {
}
// Didn't find an exact match: interpolate between two existing tables
- final int index = LOOKUP_TABLES.indexOfKey(getKey(fontScale));
+ final int index = sLookupTables.indexOfKey(getKey(fontScale));
if (index >= 0) {
// This should never happen, should have been covered by get() above.
- return LOOKUP_TABLES.valueAt(index);
+ return sLookupTables.valueAt(index);
}
// Didn't find an exact match: interpolate between two existing tables
final int lowerIndex = -(index + 1) - 1;
final int higherIndex = lowerIndex + 1;
- if (lowerIndex < 0 || higherIndex >= LOOKUP_TABLES.size()) {
+ if (lowerIndex < 0 || higherIndex >= sLookupTables.size()) {
// We have gone beyond our bounds and have nothing to interpolate between. Just give
// them a straight linear table instead.
// This works because when FontScaleConverter encounters a size beyond its bounds, it
// calculates a linear fontScale factor using the ratio of the last element pair.
- return new FontScaleConverter(new float[] {1f}, new float[] {fontScale});
+ FontScaleConverterImpl converter = new FontScaleConverterImpl(
+ new float[]{1f},
+ new float[]{fontScale}
+ );
+
+ if (Flags.fontScaleConverterPublic()) {
+ // Cache for next time.
+ put(fontScale, converter);
+ }
+
+ return converter;
} else {
- float startScale = getScaleFromKey(LOOKUP_TABLES.keyAt(lowerIndex));
- float endScale = getScaleFromKey(LOOKUP_TABLES.keyAt(higherIndex));
+ float startScale = getScaleFromKey(sLookupTables.keyAt(lowerIndex));
+ float endScale = getScaleFromKey(sLookupTables.keyAt(higherIndex));
float interpolationPoint = MathUtils.constrainedMap(
/* rangeMin= */ 0f,
/* rangeMax= */ 1f,
@@ -152,10 +185,18 @@ public class FontScaleConverterFactory {
endScale,
fontScale
);
- return createInterpolatedTableBetween(
- LOOKUP_TABLES.valueAt(lowerIndex),
- LOOKUP_TABLES.valueAt(higherIndex),
- interpolationPoint);
+ FontScaleConverter converter = createInterpolatedTableBetween(
+ sLookupTables.valueAt(lowerIndex),
+ sLookupTables.valueAt(higherIndex),
+ interpolationPoint
+ );
+
+ if (Flags.fontScaleConverterPublic()) {
+ // Cache for next time.
+ put(fontScale, converter);
+ }
+
+ return converter;
}
}
@@ -175,7 +216,7 @@ public class FontScaleConverterFactory {
dpInterpolated[i] = MathUtils.lerp(startDp, endDp, interpolationPoint);
}
- return new FontScaleConverter(commonSpSizes, dpInterpolated);
+ return new FontScaleConverterImpl(commonSpSizes, dpInterpolated);
}
private static int getKey(float fontScale) {
@@ -187,11 +228,24 @@ public class FontScaleConverterFactory {
}
private static void put(float scaleKey, @NonNull FontScaleConverter fontScaleConverter) {
- LOOKUP_TABLES.put(getKey(scaleKey), fontScaleConverter);
+ // Dollar-store CopyOnWriteSparseArray, since this is the only write op we need.
+ synchronized (LOOKUP_TABLES_WRITE_LOCK) {
+ var newTable = sLookupTables.clone();
+ putInto(newTable, scaleKey, fontScaleConverter);
+ sLookupTables = newTable;
+ }
+ }
+
+ private static void putInto(
+ SparseArray<FontScaleConverter> table,
+ float scaleKey,
+ @NonNull FontScaleConverter fontScaleConverter
+ ) {
+ table.put(getKey(scaleKey), fontScaleConverter);
}
@Nullable
private static FontScaleConverter get(float scaleKey) {
- return LOOKUP_TABLES.get(getKey(scaleKey));
+ return sLookupTables.get(getKey(scaleKey));
}
}
diff --git a/core/java/android/content/res/FontScaleConverterImpl.java b/core/java/android/content/res/FontScaleConverterImpl.java
new file mode 100644
index 000000000000..1968c4e53109
--- /dev/null
+++ b/core/java/android/content/res/FontScaleConverterImpl.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import android.annotation.NonNull;
+import android.util.MathUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+
+/**
+ * A lookup table for non-linear font scaling. Converts font sizes given in "sp" dimensions to a
+ * "dp" dimension according to a non-linear curve by interpolating values in a lookup table.
+ *
+ * {@see FontScaleConverter}
+ *
+ * @hide
+ */
+// Needs to be public so the Kotlin test can see it
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public class FontScaleConverterImpl implements FontScaleConverter {
+
+ /** @hide */
+ @VisibleForTesting
+ public final float[] mFromSpValues;
+ /** @hide */
+ @VisibleForTesting
+ public final float[] mToDpValues;
+
+ /**
+ * Creates a lookup table for the given conversions.
+ *
+ * <p>Any "sp" value not in the lookup table will be derived via linear interpolation.
+ *
+ * <p>The arrays must be sorted ascending and monotonically increasing.
+ *
+ * @param fromSp array of dimensions in SP
+ * @param toDp array of dimensions in DP that correspond to an SP value in fromSp
+ *
+ * @throws IllegalArgumentException if the array lengths don't match or are empty
+ * @hide
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public FontScaleConverterImpl(@NonNull float[] fromSp, @NonNull float[] toDp) {
+ if (fromSp.length != toDp.length || fromSp.length == 0) {
+ throw new IllegalArgumentException("Array lengths must match and be nonzero");
+ }
+
+ mFromSpValues = fromSp;
+ mToDpValues = toDp;
+ }
+
+ /**
+ * Convert a dimension in "dp" back to "sp" using the lookup table.
+ *
+ * @hide
+ */
+ @Override
+ public float convertDpToSp(float dp) {
+ return lookupAndInterpolate(dp, mToDpValues, mFromSpValues);
+ }
+
+ /**
+ * Convert a dimension in "sp" to "dp" using the lookup table.
+ *
+ * @hide
+ */
+ @Override
+ public float convertSpToDp(float sp) {
+ return lookupAndInterpolate(sp, mFromSpValues, mToDpValues);
+ }
+
+ private static float lookupAndInterpolate(
+ float sourceValue,
+ float[] sourceValues,
+ float[] targetValues
+ ) {
+ final float sourceValuePositive = Math.abs(sourceValue);
+ // TODO(b/247861374): find a match at a higher index?
+ final float sign = Math.signum(sourceValue);
+ // We search for exact matches only, even if it's just a little off. The interpolation will
+ // handle any non-exact matches.
+ final int index = Arrays.binarySearch(sourceValues, sourceValuePositive);
+ if (index >= 0) {
+ // exact match, return the matching dp
+ return sign * targetValues[index];
+ } else {
+ // must be a value in between index and index + 1: interpolate.
+ final int lowerIndex = -(index + 1) - 1;
+
+ final float startSp;
+ final float endSp;
+ final float startDp;
+ final float endDp;
+
+ if (lowerIndex >= sourceValues.length - 1) {
+ // It's past our lookup table. Determine the last elements' scaling factor and use.
+ startSp = sourceValues[sourceValues.length - 1];
+ startDp = targetValues[sourceValues.length - 1];
+
+ if (startSp == 0) return 0;
+
+ final float scalingFactor = startDp / startSp;
+ return sourceValue * scalingFactor;
+ } else if (lowerIndex == -1) {
+ // It's smaller than the smallest value in our table. Interpolate from 0.
+ startSp = 0;
+ startDp = 0;
+ endSp = sourceValues[0];
+ endDp = targetValues[0];
+ } else {
+ startSp = sourceValues[lowerIndex];
+ endSp = sourceValues[lowerIndex + 1];
+ startDp = targetValues[lowerIndex];
+ endDp = targetValues[lowerIndex + 1];
+ }
+
+ return sign
+ * MathUtils.constrainedMap(startDp, endDp, startSp, endSp, sourceValuePositive);
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null) return false;
+ if (!(o instanceof FontScaleConverterImpl)) return false;
+ FontScaleConverterImpl that = (FontScaleConverterImpl) o;
+ return Arrays.equals(mFromSpValues, that.mFromSpValues)
+ && Arrays.equals(mToDpValues, that.mToDpValues);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Arrays.hashCode(mFromSpValues);
+ result = 31 * result + Arrays.hashCode(mToDpValues);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "FontScaleConverter{"
+ + "fromSpValues="
+ + Arrays.toString(mFromSpValues)
+ + ", toDpValues="
+ + Arrays.toString(mToDpValues)
+ + '}';
+ }
+}
diff --git a/core/java/android/content/res/flags.aconfig b/core/java/android/content/res/flags.aconfig
index 3a00d91bfb9f..db81e847d6bd 100644
--- a/core/java/android/content/res/flags.aconfig
+++ b/core/java/android/content/res/flags.aconfig
@@ -10,6 +10,15 @@ flag {
}
flag {
+ name: "font_scale_converter_public"
+ namespace: "accessibility"
+ description: "Enables the public API for FontScaleConverter, including enabling thread-safe caching."
+ bug: "239736383"
+ # fixed_read_only or device wont boot because of permission issues accessing flags during boot
+ is_fixed_read_only: true
+}
+
+flag {
name: "asset_file_descriptor_frro"
namespace: "resource_manager"
description: "Feature flag for passing in an AssetFileDescriptor to create an frro"
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 145dbf21699e..cb9c3335518a 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -17,6 +17,7 @@
package android.hardware.input;
import static com.android.hardware.input.Flags.keyboardA11yBounceKeysFlag;
+import static com.android.hardware.input.Flags.keyboardA11yStickyKeysFlag;
import android.Manifest;
import android.annotation.FloatRange;
@@ -401,4 +402,49 @@ public class InputSettings {
UserHandle.USER_CURRENT);
}
+ /**
+ * Whether Accessibility sticky keys is enabled.
+ *
+ * <p>
+ * 'Sticky keys' is an accessibility feature that assists users who have physical
+ * disabilities or help users reduce repetitive strain injury. It serializes keystrokes
+ * instead of pressing multiple keys at a time, allowing the user to press and release a
+ * modifier key, such as Shift, Ctrl, Alt, or any other modifier key, and have it remain
+ * active until any other key is pressed.
+ * </p>
+ *
+ * @hide
+ */
+ public static boolean isAccessibilityStickyKeysEnabled(@NonNull Context context) {
+ if (!keyboardA11yStickyKeysFlag()) {
+ return false;
+ }
+ return Settings.System.getIntForUser(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_STICKY_KEYS, 0, UserHandle.USER_CURRENT) != 0;
+ }
+
+ /**
+ * Set Accessibility sticky keys feature enabled/disabled.
+ *
+ * <p>
+ * 'Sticky keys' is an accessibility feature that assists users who have physical
+ * disabilities or help users reduce repetitive strain injury. It serializes keystrokes
+ * instead of pressing multiple keys at a time, allowing the user to press and release a
+ * modifier key, such as Shift, Ctrl, Alt, or any other modifier key, and have it remain
+ * active until any other key is pressed.
+ * </p>
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+ public static void setAccessibilityStickyKeysEnabled(@NonNull Context context,
+ boolean enabled) {
+ if (!keyboardA11yStickyKeysFlag()) {
+ return;
+ }
+ Settings.System.putIntForUser(context.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_STICKY_KEYS, enabled ? 1 : 0,
+ UserHandle.USER_CURRENT);
+ }
+
}
diff --git a/core/java/android/os/HidlSupport.java b/core/java/android/os/HidlSupport.java
index 91b796aba655..77160557f5c2 100644
--- a/core/java/android/os/HidlSupport.java
+++ b/core/java/android/os/HidlSupport.java
@@ -218,6 +218,13 @@ public class HidlSupport {
@SystemApi
public static native int getPidIfSharable();
+ /**
+ * Return true if HIDL is supported on this device and false if not.
+ *
+ * @hide
+ */
+ public static native boolean isHidlSupported();
+
/** @hide */
public HidlSupport() {}
}
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index feed20800fd4..bc19655d1618 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -18,6 +18,7 @@ package android.os;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.util.Log;
import libcore.util.NativeAllocationRegistry;
@@ -78,6 +79,17 @@ public abstract class HwBinder implements IHwBinder {
String iface,
String serviceName)
throws RemoteException, NoSuchElementException {
+ if (!HidlSupport.isHidlSupported()
+ && (iface.equals("android.hidl.manager@1.0::IServiceManager")
+ || iface.equals("android.hidl.manager@1.1::IServiceManager")
+ || iface.equals("android.hidl.manager@1.2::IServiceManager"))) {
+ Log.i(
+ TAG,
+ "Replacing Java hwservicemanager with a fake HwNoService"
+ + " because HIDL is not supported on this device.");
+ return new HwNoService();
+ }
+
return getService(iface, serviceName, false /* retry */);
}
/**
diff --git a/core/java/android/os/HwNoService.java b/core/java/android/os/HwNoService.java
new file mode 100644
index 000000000000..117c3ad7ee48
--- /dev/null
+++ b/core/java/android/os/HwNoService.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * A fake hwservicemanager that is used locally when HIDL isn't supported on the device.
+ *
+ * @hide
+ */
+final class HwNoService implements IHwBinder, IHwInterface {
+ /** @hide */
+ @Override
+ public void transact(int code, HwParcel request, HwParcel reply, int flags) {}
+
+ /** @hide */
+ @Override
+ public IHwInterface queryLocalInterface(String descriptor) {
+ return new HwNoService();
+ }
+
+ /** @hide */
+ @Override
+ public boolean linkToDeath(DeathRecipient recipient, long cookie) {
+ return true;
+ }
+
+ /** @hide */
+ @Override
+ public boolean unlinkToDeath(DeathRecipient recipient) {
+ return true;
+ }
+
+ /** @hide */
+ @Override
+ public IHwBinder asBinder() {
+ return this;
+ }
+}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7e07e1f2e499..fc8523ee23dd 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -1599,7 +1599,7 @@ public class Process {
* fully removed, otherwise system resources may leak.
* @hide
*/
- public static final native int sendSignalToProcessGroup(int uid, int pid, int signal);
+ public static final native boolean sendSignalToProcessGroup(int uid, int pid, int signal);
/**
* Freeze the cgroup for the given UID.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2cc56d838b79..4af657dab0cd 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7330,7 +7330,7 @@ public final class Settings {
"hearing_aid_media_routing";
/**
- * System sounds routing value for hearing aid. It routes system sounds to hearing aid
+ * Notification routing value for hearing aid. It routes notification sounds to hearing aid
* or device speaker.
* <ul>
* <li> 0 = Default
@@ -7339,8 +7339,8 @@ public final class Settings {
* </ul>
* @hide
*/
- public static final String HEARING_AID_SYSTEM_SOUNDS_ROUTING =
- "hearing_aid_system_sounds_routing";
+ public static final String HEARING_AID_NOTIFICATION_ROUTING =
+ "hearing_aid_notification_routing";
/**
* Setting to indicate that on device captions are enabled.
@@ -7801,6 +7801,15 @@ public final class Settings {
public static final String ACCESSIBILITY_BOUNCE_KEYS = "accessibility_bounce_keys";
/**
+ * Whether to enable sticky keys for Physical Keyboard accessibility.
+ *
+ * This is a boolean value that determines if Sticky keys feature is enabled.
+ *
+ * @hide
+ */
+ public static final String ACCESSIBILITY_STICKY_KEYS = "accessibility_sticky_keys";
+
+ /**
* Whether stylus button presses are disabled. This is a boolean that
* determines if stylus buttons are ignored.
*
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index e3d9c605ff63..1712fd3c3323 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -122,7 +122,6 @@ import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.window.ITrustedPresentationListener;
import android.window.TaskFpsCallback;
import android.window.TrustedPresentationThresholds;
@@ -1280,9 +1279,8 @@ public interface WindowManager extends ViewManager {
* android:value="true|false"/&gt;
* &lt;/application&gt;
* </pre>
- * @hide
*/
- // TODO(b/279428317): Make this public API.
+ @FlaggedApi(Flags.FLAG_APP_COMPAT_PROPERTIES_API)
String PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE =
"android.window.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE";
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 966161fd642a..19ba316257a3 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -45,6 +45,7 @@ import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
import android.os.Trace;
+import android.service.contentcapture.ContentCaptureService;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextUtils;
@@ -69,6 +70,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
@@ -152,7 +154,16 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
public ComponentName mComponentName;
/**
- * List of events held to be sent as a batch.
+ * Thread-safe queue of events held to be processed as a batch.
+ *
+ * Because it is not guaranteed that the events will be enqueued from a single thread, the
+ * implementation must be thread-safe to prevent unexpected behaviour.
+ */
+ @NonNull
+ private final ConcurrentLinkedQueue<ContentCaptureEvent> mEventProcessQueue;
+
+ /**
+ * List of events held to be sent to the {@link ContentCaptureService} as a batch.
*
* @hide
*/
@@ -238,6 +249,8 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
mFlushHistory = logHistorySize > 0 ? new LocalLog(logHistorySize) : null;
mSessionStateReceiver = new SessionStateReceiver(this);
+
+ mEventProcessQueue = new ConcurrentLinkedQueue<>();
}
@Override
@@ -733,6 +746,9 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
}
mDirectServiceInterface = null;
mContentProtectionEventProcessor = null;
+ if (runOnBackgroundThreadEnabled()) {
+ mEventProcessQueue.clear();
+ }
}
// TODO(b/122454205): once we support multiple sessions, we might need to move some of these
@@ -823,27 +839,30 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
// change should also get get rid of the "internalNotifyXXXX" methods above
void notifyChildSessionStarted(int parentSessionId, int childSessionId,
@NonNull ContentCaptureContext clientContext) {
- runOnContentCaptureThread(
- () -> sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
- .setParentSessionId(parentSessionId).setClientContext(clientContext),
- FORCE_FLUSH));
+ final ContentCaptureEvent event =
+ new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
+ .setParentSessionId(parentSessionId)
+ .setClientContext(clientContext);
+ enqueueEvent(event, FORCE_FLUSH);
}
void notifyChildSessionFinished(int parentSessionId, int childSessionId) {
- runOnContentCaptureThread(
- () -> sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
- .setParentSessionId(parentSessionId), FORCE_FLUSH));
+ final ContentCaptureEvent event =
+ new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
+ .setParentSessionId(parentSessionId);
+ enqueueEvent(event, FORCE_FLUSH);
}
void notifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) {
- runOnContentCaptureThread(() ->
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
- .setViewNode(node.mNode)));
+ final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
+ .setViewNode(node.mNode);
+ enqueueEvent(event);
}
void notifyViewDisappeared(int sessionId, @NonNull AutofillId id) {
- runOnContentCaptureThread(() -> sendEvent(
- new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id)));
+ final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED)
+ .setAutofillId(id);
+ enqueueEvent(event);
}
void notifyViewTextChanged(int sessionId, @NonNull AutofillId id, @Nullable CharSequence text) {
@@ -867,50 +886,90 @@ public final class MainContentCaptureSession extends ContentCaptureSession {
final int startIndex = Selection.getSelectionStart(text);
final int endIndex = Selection.getSelectionEnd(text);
- runOnContentCaptureThread(() -> sendEvent(
- new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED)
- .setAutofillId(id).setText(eventText)
- .setComposingIndex(composingStart, composingEnd)
- .setSelectionIndex(startIndex, endIndex)));
+
+ final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED)
+ .setAutofillId(id).setText(eventText)
+ .setComposingIndex(composingStart, composingEnd)
+ .setSelectionIndex(startIndex, endIndex);
+ enqueueEvent(event);
}
void notifyViewInsetsChanged(int sessionId, @NonNull Insets viewInsets) {
- runOnContentCaptureThread(() ->
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED)
- .setInsets(viewInsets)));
+ final ContentCaptureEvent event =
+ new ContentCaptureEvent(sessionId, TYPE_VIEW_INSETS_CHANGED)
+ .setInsets(viewInsets);
+ enqueueEvent(event);
}
void notifyViewTreeEvent(int sessionId, boolean started) {
final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED;
final boolean disableFlush = mManager.getFlushViewTreeAppearingEventDisabled();
+ final boolean forceFlush = disableFlush ? !started : FORCE_FLUSH;
- runOnContentCaptureThread(() -> sendEvent(
- new ContentCaptureEvent(sessionId, type),
- disableFlush ? !started : FORCE_FLUSH));
+ final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type);
+ enqueueEvent(event, forceFlush);
}
void notifySessionResumed(int sessionId) {
- runOnContentCaptureThread(() -> sendEvent(
- new ContentCaptureEvent(sessionId, TYPE_SESSION_RESUMED), FORCE_FLUSH));
+ final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_SESSION_RESUMED);
+ enqueueEvent(event, FORCE_FLUSH);
}
void notifySessionPaused(int sessionId) {
- runOnContentCaptureThread(() -> sendEvent(
- new ContentCaptureEvent(sessionId, TYPE_SESSION_PAUSED), FORCE_FLUSH));
+ final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_SESSION_PAUSED);
+ enqueueEvent(event, FORCE_FLUSH);
}
void notifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) {
- runOnContentCaptureThread(() ->
- sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
- .setClientContext(context), FORCE_FLUSH));
+ final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
+ .setClientContext(context);
+ enqueueEvent(event, FORCE_FLUSH);
}
/** public because is also used by ViewRootImpl */
public void notifyWindowBoundsChanged(int sessionId, @NonNull Rect bounds) {
- runOnContentCaptureThread(() -> sendEvent(
+ final ContentCaptureEvent event =
new ContentCaptureEvent(sessionId, TYPE_WINDOW_BOUNDS_CHANGED)
- .setBounds(bounds)
- ));
+ .setBounds(bounds);
+ enqueueEvent(event);
+ }
+
+ private List<ContentCaptureEvent> clearBufferEvents() {
+ final ArrayList<ContentCaptureEvent> bufferEvents = new ArrayList<>();
+ ContentCaptureEvent event;
+ while ((event = mEventProcessQueue.poll()) != null) {
+ bufferEvents.add(event);
+ }
+ return bufferEvents;
+ }
+
+ private void enqueueEvent(@NonNull final ContentCaptureEvent event) {
+ enqueueEvent(event, /* forceFlush */ false);
+ }
+
+ /**
+ * Enqueue the event into {@code mEventProcessBuffer} if it is not an urgent request. Otherwise,
+ * clear the buffer events then starting sending out current event.
+ */
+ private void enqueueEvent(@NonNull final ContentCaptureEvent event, boolean forceFlush) {
+ if (runOnBackgroundThreadEnabled()) {
+ if (forceFlush) {
+ // The buffer events are cleared in the same thread first to prevent new events
+ // being added during the time of context switch. This would disrupt the sequence
+ // of events.
+ final List<ContentCaptureEvent> batchEvents = clearBufferEvents();
+ runOnContentCaptureThread(() -> {
+ for (int i = 0; i < batchEvents.size(); i++) {
+ sendEvent(batchEvents.get(i));
+ }
+ sendEvent(event, /* forceFlush= */ true);
+ });
+ } else {
+ mEventProcessQueue.offer(event);
+ }
+ } else {
+ mHandler.post(() -> sendEvent(event, forceFlush));
+ }
}
/** public because is also used by ViewRootImpl */
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 8ad10af7250a..0d499a1b311e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1014,6 +1014,11 @@ public class RemoteViews implements Parcelable, Filter {
public int getActionTag() {
return SET_PENDING_INTENT_TEMPLATE_TAG;
}
+
+ @Override
+ public void visitUris(@NonNull Consumer<Uri> visitor) {
+ mPendingIntentTemplate.visitUris(visitor);
+ }
}
/**
@@ -1428,9 +1433,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public void visitUris(@NonNull Consumer<Uri> visitor) {
- // TODO(b/281044385): Maybe visit intent URIs. This may require adding a dedicated
- // visitUris method in the Intent class, since it can contain other intents. Otherwise,
- // the basic thing to do here would be just visitor.accept(intent.getData()).
+ mIntent.visitUris(visitor);
}
}
@@ -1510,7 +1513,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public void visitUris(@NonNull Consumer<Uri> visitor) {
- // TODO(b/281044385): Maybe visit intent URIs in the RemoteResponse.
+ mResponse.visitUris(visitor);
}
}
@@ -1559,6 +1562,11 @@ public class RemoteViews implements Parcelable, Filter {
public int getActionTag() {
return SET_ON_STYLUS_HANDWRITING_RESPONSE_TAG;
}
+
+ @Override
+ public void visitUris(@NonNull Consumer<Uri> visitor) {
+ mPendingIntent.visitUris(visitor);
+ }
}
/**
@@ -1632,7 +1640,7 @@ public class RemoteViews implements Parcelable, Filter {
@Override
public void visitUris(@NonNull Consumer<Uri> visitor) {
- // TODO(b/281044385): Maybe visit intent URIs in the RemoteResponse.
+ mResponse.visitUris(visitor);
}
}
@@ -2193,6 +2201,10 @@ public class RemoteViews implements Parcelable, Filter {
final Icon icon = (Icon) getParameterValue(null);
if (icon != null) visitIconUri(icon, visitor);
break;
+ case INTENT:
+ final Intent intent = (Intent) getParameterValue(null);
+ if (intent != null) intent.visitUris(visitor);
+ break;
// TODO(b/281044385): Should we do anything about type BUNDLE?
}
}
@@ -6972,6 +6984,20 @@ public class RemoteViews implements Parcelable, Filter {
mElementNames = parcel.createStringArrayList();
}
+ /**
+ * See {@link RemoteViews#visitUris(Consumer)}.
+ *
+ * @hide
+ */
+ public void visitUris(@NonNull Consumer<Uri> visitor) {
+ if (mPendingIntent != null) {
+ mPendingIntent.visitUris(visitor);
+ }
+ if (mFillIntent != null) {
+ mFillIntent.visitUris(visitor);
+ }
+ }
+
private void handleViewInteraction(
View v,
InteractionHandler handler) {
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index 727bff44017e..0077dab7ff63 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -23,3 +23,16 @@ flag {
bug: "297550533"
is_fixed_read_only: true
}
+
+flag {
+ name: "app_compat_properties_api"
+ namespace: "large_screen_experiences_app_compat"
+ description: "Whether app compat property APIs are public. Which includes: /n"
+ "WindowManager.PROPERTY_COMPAT_ALLOW_MIN_ASPECT_RATIO_OVERRIDE,/n"
+ "WindowManager.PROPERTY_COMPAT_ALLOW_IGNORING_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED,/n"
+ "WindowManager.PROPERTY_COMPAT_ALLOW_RESIZEABLE_ACTIVITY_OVERRIDES,/n"
+ "WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE,/n"
+ "WindowManager.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE"
+ bug: "316139088"
+ is_fixed_read_only: true
+}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 7e2c0179b327..86d3037b1612 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -24,7 +24,9 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROS
import static android.content.ContentProvider.getUserIdFromUri;
import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL;
import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK;
+
import static com.android.internal.util.LatencyTracker.ACTION_LOAD_SHARE_SHEET;
+
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.animation.Animator;
@@ -2868,7 +2870,6 @@ public class ChooserActivity extends ResolverActivity implements
@Override
public void onListRebuilt(ResolverListAdapter listAdapter, boolean rebuildComplete) {
setupScrollListener();
- maybeSetupGlobalLayoutListener();
ChooserListAdapter chooserListAdapter = (ChooserListAdapter) listAdapter;
if (chooserListAdapter.getUserHandle()
@@ -2970,28 +2971,6 @@ public class ChooserActivity extends ResolverActivity implements
});
}
- private void maybeSetupGlobalLayoutListener() {
- if (shouldShowTabs()) {
- return;
- }
- final View recyclerView = mChooserMultiProfilePagerAdapter.getActiveAdapterView();
- recyclerView.getViewTreeObserver()
- .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- // Fixes an issue were the accessibility border disappears on list creation.
- recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- final TextView titleView = findViewById(R.id.title);
- if (titleView != null) {
- titleView.setFocusable(true);
- titleView.setFocusableInTouchMode(true);
- titleView.requestFocus();
- titleView.requestAccessibilityFocus();
- }
- }
- });
- }
-
@Override // ChooserListCommunicator
public boolean isSendAction(Intent targetIntent) {
if (targetIntent == null) {
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index f1aa330f562c..efc1455ecd45 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -39,7 +39,6 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
-import android.content.pm.UserPackage;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -309,8 +308,7 @@ public class SuspendedAppActivity extends AlertActivity
try {
final String[] errored = ipm.setPackagesSuspendedAsUser(
new String[]{mSuspendedPackage}, false, null, null, null, 0,
- mSuspendingPackage, mUserId /* suspendingUserId */,
- mUserId /* targetUserId */);
+ mSuspendingPackage, mUserId);
if (ArrayUtils.contains(errored, mSuspendedPackage)) {
Slog.e(TAG, "Could not unsuspend " + mSuspendedPackage);
break;
@@ -352,18 +350,17 @@ public class SuspendedAppActivity extends AlertActivity
}
public static Intent createSuspendedAppInterceptIntent(String suspendedPackage,
- UserPackage suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options,
+ String suspendingPackage, SuspendDialogInfo dialogInfo, Bundle options,
IntentSender onUnsuspend, int userId) {
- Intent intent = new Intent()
+ return new Intent()
.setClassName("android", SuspendedAppActivity.class.getName())
.putExtra(EXTRA_SUSPENDED_PACKAGE, suspendedPackage)
.putExtra(EXTRA_DIALOG_INFO, dialogInfo)
- .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage.packageName)
+ .putExtra(EXTRA_SUSPENDING_PACKAGE, suspendingPackage)
.putExtra(EXTRA_UNSUSPEND_INTENT, onUnsuspend)
.putExtra(EXTRA_ACTIVITY_OPTIONS, options)
.putExtra(Intent.EXTRA_USER_ID, userId)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- return intent;
}
}
diff --git a/core/java/com/android/internal/jank/InteractionJankMonitor.java b/core/java/com/android/internal/jank/InteractionJankMonitor.java
index 8b1879f5225d..0ec8b7461221 100644
--- a/core/java/com/android/internal/jank/InteractionJankMonitor.java
+++ b/core/java/com/android/internal/jank/InteractionJankMonitor.java
@@ -117,8 +117,6 @@ public class InteractionJankMonitor {
@Deprecated public static final int CUJ_NOTIFICATION_SHADE_ROW_SWIPE = Cuj.CUJ_NOTIFICATION_SHADE_ROW_SWIPE;
@Deprecated public static final int CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE;
@Deprecated public static final int CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE = Cuj.CUJ_NOTIFICATION_SHADE_QS_SCROLL_SWIPE;
- @Deprecated public static final int CUJ_LAUNCHER_APP_CLOSE_TO_HOME = Cuj.CUJ_LAUNCHER_APP_CLOSE_TO_HOME;
- @Deprecated public static final int CUJ_LAUNCHER_QUICK_SWITCH = Cuj.CUJ_LAUNCHER_QUICK_SWITCH;
@Deprecated public static final int CUJ_NOTIFICATION_HEADS_UP_APPEAR = Cuj.CUJ_NOTIFICATION_HEADS_UP_APPEAR;
@Deprecated public static final int CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR = Cuj.CUJ_NOTIFICATION_HEADS_UP_DISAPPEAR;
@Deprecated public static final int CUJ_NOTIFICATION_ADD = Cuj.CUJ_NOTIFICATION_ADD;
diff --git a/core/jni/android_os_HidlSupport.cpp b/core/jni/android_os_HidlSupport.cpp
index e3602d8f5c72..3e51e9315d89 100644
--- a/core/jni/android_os_HidlSupport.cpp
+++ b/core/jni/android_os_HidlSupport.cpp
@@ -15,6 +15,7 @@
*/
#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"
@@ -24,8 +25,13 @@ static jint android_os_HidlSupport_getPidIfSharable(JNIEnv*, jclass) {
return android::hardware::details::getPidIfSharable();
}
+static jboolean android_os_HidlSupport_isHidlSupported(JNIEnv*, jclass) {
+ return android::hardware::isHidlSupported();
+}
+
static const JNINativeMethod gHidlSupportMethods[] = {
- {"getPidIfSharable", "()I", (void*)android_os_HidlSupport_getPidIfSharable},
+ {"getPidIfSharable", "()I", (void*)android_os_HidlSupport_getPidIfSharable},
+ {"isHidlSupported", "()Z", (void*)android_os_HidlSupport_isHidlSupported},
};
const char* const kHidlSupportPathName = "android/os/HidlSupport";
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 55100a5347fd..7af69f2dff08 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -1262,7 +1262,7 @@ jint android_os_Process_killProcessGroup(JNIEnv* env, jobject clazz, jint uid, j
return killProcessGroup(uid, pid, SIGKILL);
}
-jint android_os_Process_sendSignalToProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid,
+jboolean android_os_Process_sendSignalToProcessGroup(JNIEnv* env, jobject clazz, jint uid, jint pid,
jint signal) {
if (uid < 0) {
return jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
@@ -1344,7 +1344,7 @@ static const JNINativeMethod methods[] = {
//{"setApplicationObject", "(Landroid/os/IBinder;)V",
//(void*)android_os_Process_setApplicationObject},
{"killProcessGroup", "(II)I", (void*)android_os_Process_killProcessGroup},
- {"sendSignalToProcessGroup", "(III)I", (void*)android_os_Process_sendSignalToProcessGroup},
+ {"sendSignalToProcessGroup", "(III)Z", (void*)android_os_Process_sendSignalToProcessGroup},
{"removeAllProcessGroups", "()V", (void*)android_os_Process_removeAllProcessGroups},
{"nativePidFdOpen", "(II)I", (void*)android_os_Process_nativePidFdOpen},
{"freezeCgroupUid", "(IZ)V", (void*)android_os_Process_freezeCgroupUID},
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 9ca1849dedc2..104c023f550d 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -93,7 +93,7 @@ message SecureSettingsProto {
optional SettingProto hearing_aid_ringtone_routing = 46 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto hearing_aid_call_routing = 47 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto hearing_aid_media_routing = 48 [ (android.privacy).dest = DEST_AUTOMATIC ];
- optional SettingProto hearing_aid_system_sounds_routing = 49 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto hearing_aid_notification_routing = 49 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto accessibility_magnification_joystick_enabled = 50 [ (android.privacy).dest = DEST_AUTOMATIC ];
// Settings for font scaling
optional SettingProto accessibility_font_scaling_has_been_changed = 51 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 404fa39fb6ed..382a82cd090e 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -394,6 +394,7 @@ message ActivityRecordProto {
optional bool should_force_rotate_for_camera_compat = 39;
optional bool should_refresh_activity_for_camera_compat = 40;
optional bool should_refresh_activity_via_pause_for_camera_compat = 41;
+ optional bool should_override_min_aspect_ratio = 42;
}
/* represents WindowToken */
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0264fdc198f3..c6209dd25c47 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5189,7 +5189,9 @@
this permission, it must hold the permission and be the active VoiceInteractionService in
the system.
{@see Settings.Secure.VOICE_INTERACTION_SERVICE}
- @hide -->
+ @hide @SystemApi Intended for OEM and system apps.
+ <p>Protection level: signature|privileged
+ -->
<permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"
android:protectionLevel="signature|privileged" />
@@ -5198,7 +5200,9 @@
sound models at any time. This permission should be reserved for system enrollment
applications detected by {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}
only.
- @hide <p>Not for use by third-party applications.</p> -->
+ @hide @SystemApi Intended for OEM and system apps.
+ <p>Protection level: signature|privileged
+ -->
<permission android:name="android.permission.KEYPHRASE_ENROLLMENT_APPLICATION"
android:protectionLevel="signature|privileged" />
@@ -5702,11 +5706,10 @@
android:protectionLevel="normal" />
<!-- @hide @FlaggedApi("android.companion.flags.companion_transport_apis")
- @SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)
Allows an application to send and receive messages via CDM transports.
-->
<permission android:name="android.permission.USE_COMPANION_TRANSPORTS"
- android:protectionLevel="signature|module" />
+ android:protectionLevel="signature" />
<!-- Allows an application to create new companion device associations.
@SystemApi
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
index ba6c8fab48d4..8308e7c5ef19 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
@@ -16,24 +16,35 @@
package android.content.res
-
import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
import androidx.core.util.forEach
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Rule
import kotlin.math.ceil
import kotlin.math.floor
import org.junit.Test
import org.junit.runner.RunWith
+import java.lang.IllegalStateException
import kotlin.random.Random.Default.nextFloat
+/**
+ * Unit tests for FontScaleConverterFactory. Note that some similar tests are in
+ * cts/tests/tests/content/src/android/content/res/cts/FontScaleConverterFactoryTest.kt
+ */
@Presubmit
@RunWith(AndroidJUnit4::class)
class FontScaleConverterFactoryTest {
+ @get:Rule
+ val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+
@Test
fun scale200IsTwiceAtSmallSizes() {
val table = FontScaleConverterFactory.forScale(2F)!!
@@ -61,19 +72,6 @@ class FontScaleConverterFactoryTest {
assertThat(table.convertSpToDp(100F)).isWithin(CONVERSION_TOLERANCE).of(300f)
}
- @SmallTest
- fun missingLookupTable110_returnsInterpolated() {
- val table = FontScaleConverterFactory.forScale(1.1F)!!
-
- assertThat(table.convertSpToDp(1F)).isWithin(CONVERSION_TOLERANCE).of(1.1f)
- assertThat(table.convertSpToDp(8F)).isWithin(CONVERSION_TOLERANCE).of(8f * 1.1f)
- assertThat(table.convertSpToDp(10F)).isWithin(CONVERSION_TOLERANCE).of(11f)
- assertThat(table.convertSpToDp(5F)).isWithin(CONVERSION_TOLERANCE).of(5f * 1.1f)
- assertThat(table.convertSpToDp(0F)).isWithin(CONVERSION_TOLERANCE).of(0f)
- assertThat(table.convertSpToDp(50F)).isLessThan(50f * 1.1f)
- assertThat(table.convertSpToDp(100F)).isLessThan(100f * 1.1f)
- }
-
@Test
fun missingLookupTable199_returnsInterpolated() {
val table = FontScaleConverterFactory.forScale(1.9999F)!!
@@ -96,21 +94,51 @@ class FontScaleConverterFactoryTest {
assertThat(table.convertSpToDp(0F)).isWithin(CONVERSION_TOLERANCE).of(0f)
}
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC)
+ fun missingLookupTable_cachesInterpolated() {
+ val table = FontScaleConverterFactory.forScale(1.6F)!!
+
+ assertThat(FontScaleConverterFactory.sLookupTables.contains((1.6F * 100).toInt())).isTrue()
+ // Double check known existing values
+ assertThat(FontScaleConverterFactory.sLookupTables.contains((1.5F * 100).toInt())).isTrue()
+ assertThat(FontScaleConverterFactory.sLookupTables.contains((1.7F * 100).toInt())).isFalse()
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_FONT_SCALE_CONVERTER_PUBLIC)
+ fun missingLookupTablePastEnd_cachesLinear() {
+ val table = FontScaleConverterFactory.forScale(3F)!!
+
+ assertThat(FontScaleConverterFactory.sLookupTables.contains((3F * 100).toInt())).isTrue()
+ // Double check known existing values
+ assertThat(FontScaleConverterFactory.sLookupTables.contains((1.5F * 100).toInt())).isTrue()
+ assertThat(FontScaleConverterFactory.sLookupTables.contains((1.7F * 100).toInt())).isFalse()
+ }
+
@SmallTest
+ @Test
fun missingLookupTableNegativeReturnsNull() {
assertThat(FontScaleConverterFactory.forScale(-1F)).isNull()
}
@SmallTest
+ @Test
fun unnecessaryFontScalesReturnsNull() {
assertThat(FontScaleConverterFactory.forScale(0F)).isNull()
assertThat(FontScaleConverterFactory.forScale(1F)).isNull()
+ assertThat(FontScaleConverterFactory.forScale(1.1F)).isNull()
assertThat(FontScaleConverterFactory.forScale(0.85F)).isNull()
}
@SmallTest
+ @Test
fun tablesMatchAndAreMonotonicallyIncreasing() {
- FontScaleConverterFactory.LOOKUP_TABLES.forEach { _, lookupTable ->
+ FontScaleConverterFactory.sLookupTables.forEach { _, lookupTable ->
+ if (lookupTable !is FontScaleConverterImpl) {
+ throw IllegalStateException("Didn't return a FontScaleConverterImpl")
+ }
+
assertThat(lookupTable.mToDpValues).hasLength(lookupTable.mFromSpValues.size)
assertThat(lookupTable.mToDpValues).isNotEmpty()
@@ -123,6 +151,7 @@ class FontScaleConverterFactoryTest {
}
@SmallTest
+ @Test
fun testIsNonLinearFontScalingActive() {
assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(1f)).isFalse()
assertThat(FontScaleConverterFactory.isNonLinearFontScalingActive(0f)).isFalse()
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt
index bfa8c9ada911..2c614424a9a5 100644
--- a/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt
@@ -86,13 +86,13 @@ class FontScaleConverterTest {
}
private fun createTable(vararg pairs: Pair<Float, Float>) =
- FontScaleConverter(
+ FontScaleConverterImpl(
pairs.map { it.first }.toFloatArray(),
pairs.map { it.second }.toFloatArray()
)
private fun verifyConversionBothWays(
- table: FontScaleConverter,
+ table: FontScaleConverterImpl,
expectedDp: Float,
spToConvert: Float
) {
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index c8ea3742b3aa..15c90474c017 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -34,9 +34,6 @@ import android.app.PendingIntent;
import android.appwidget.AppWidgetHostView;
import android.content.Context;
import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.AsyncTask;
@@ -837,6 +834,33 @@ public class RemoteViewsTest {
}
@Test
+ public void visitUris_intents() {
+ RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
+
+ Uri fillIntentUri = Uri.parse("content://intent/fill");
+ views.setOnCheckedChangeResponse(
+ R.id.layout,
+ RemoteViews.RemoteResponse.fromFillInIntent(new Intent("action", fillIntentUri)));
+
+ Uri pendingIntentUri = Uri.parse("content://intent/pending");
+ PendingIntent pendingIntent = getPendingIntentWithUri(pendingIntentUri);
+ views.setOnClickResponse(
+ R.id.layout,
+ RemoteViews.RemoteResponse.fromPendingIntent(pendingIntent));
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ views.visitUris(visitor);
+ verify(visitor, times(1)).accept(eq(fillIntentUri));
+ verify(visitor, times(1)).accept(eq(pendingIntentUri));
+ }
+
+ private PendingIntent getPendingIntentWithUri(Uri uri) {
+ return PendingIntent.getActivity(mContext, 0,
+ new Intent("action", uri),
+ PendingIntent.FLAG_IMMUTABLE);
+ }
+
+ @Test
public void layoutInflaterFactory_nothingSet_returnsNull() {
final RemoteViews rv = new RemoteViews(mPackage, R.layout.remote_views_test);
assertNull(rv.getLayoutInflaterFactory());
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 3e7f99b96421..ed8c4f31306b 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -344,7 +344,9 @@ class TaskFragmentContainer {
if (activities == null) {
return null;
}
- return new ActivityStack(activities, isEmpty(), mToken);
+ // Already checked nullity in collectNonFinishingActivities.
+ final Rect bounds = getInfo().getConfiguration().windowConfiguration.getBounds();
+ return new ActivityStack(activities, isEmpty(), mToken, bounds, mOverlayTag);
}
/** Adds the activity that will be reparented to this container. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt
index e57f02c71e44..bd4708259b50 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt
@@ -40,7 +40,13 @@ class BubbleEducationController(private val context: Context) {
/** Whether education view should show for the collapsed stack. */
fun shouldShowStackEducation(bubble: BubbleViewProvider?): Boolean {
- val shouldShow = bubble != null &&
+ if (BubbleDebugConfig.neverShowUserEducation(context)) {
+ logDebug("Show stack edu: never")
+ return false
+ }
+
+ val shouldShow =
+ bubble != null &&
bubble.isConversationBubble && // show education for conversation bubbles only
(!hasSeenStackEducation || BubbleDebugConfig.forceShowUserEducation(context))
logDebug("Show stack edu: $shouldShow")
@@ -49,7 +55,13 @@ class BubbleEducationController(private val context: Context) {
/** Whether the educational view should show for the expanded view "manage" menu. */
fun shouldShowManageEducation(bubble: BubbleViewProvider?): Boolean {
- val shouldShow = bubble != null &&
+ if (BubbleDebugConfig.neverShowUserEducation(context)) {
+ logDebug("Show manage edu: never")
+ return false
+ }
+
+ val shouldShow =
+ bubble != null &&
bubble.isConversationBubble && // show education for conversation bubbles only
(!hasSeenManageEducation || BubbleDebugConfig.forceShowUserEducation(context))
logDebug("Show manage edu: $shouldShow")
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 7f34ee0cdd3d..f794fef48f27 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -23,6 +23,8 @@ import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
import android.util.Log;
+import android.util.Size;
+import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -33,6 +35,7 @@ import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix;
+import com.android.wm.shell.common.magnetictarget.MagnetizedObject.MagneticTarget;
/**
* Helper class to animate a {@link BubbleBarExpandedView} on a bubble.
@@ -44,6 +47,13 @@ public class BubbleBarAnimationHelper {
private static final float EXPANDED_VIEW_ANIMATE_SCALE_AMOUNT = 0.1f;
private static final float EXPANDED_VIEW_ANIMATE_OUT_SCALE_AMOUNT = .75f;
private static final int EXPANDED_VIEW_ALPHA_ANIMATION_DURATION = 150;
+ private static final int EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION = 100;
+ /**
+ * Additional scale applied to expanded view when it is positioned inside a magnetic target.
+ */
+ private static final float EXPANDED_VIEW_IN_TARGET_SCALE = 0.75f;
+ private static final int EXPANDED_VIEW_ANIMATE_POSITION_DURATION = 300;
+ private static final int EXPANDED_VIEW_DISMISS_DURATION = 250;
/** Spring config for the expanded view scale-in animation. */
private final PhysicsAnimator.SpringConfig mScaleInSpringConfig =
@@ -181,7 +191,8 @@ public class BubbleBarAnimationHelper {
Log.w(TAG, "Trying to animate collapse without a bubble");
return;
}
-
+ bbev.setScaleX(1f);
+ bbev.setScaleY(1f);
mExpandedViewContainerMatrix.setScaleX(1f);
mExpandedViewContainerMatrix.setScaleY(1f);
@@ -209,11 +220,124 @@ public class BubbleBarAnimationHelper {
}
/**
+ * Animates dismissal of currently expanded bubble
+ *
+ * @param endRunnable a runnable to run at the end of the animation
+ */
+ public void animateDismiss(Runnable endRunnable) {
+ mIsExpanded = false;
+ final BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
+ Log.w(TAG, "Trying to animate dismiss without a bubble");
+ return;
+ }
+
+ int[] location = bbev.getLocationOnScreen();
+ int diffFromBottom = mPositioner.getScreenRect().bottom - location[1];
+
+ bbev.animate()
+ // 2x distance from bottom so the view flies out
+ .translationYBy(diffFromBottom * 2)
+ .setDuration(EXPANDED_VIEW_DISMISS_DURATION)
+ .withEndAction(endRunnable)
+ .start();
+ }
+
+ /**
+ * Animate current expanded bubble back to its rest position
+ */
+ public void animateToRestPosition() {
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
+ Log.w(TAG, "Trying to animate expanded view to rest position without a bubble");
+ return;
+ }
+ Point restPoint = getExpandedViewRestPosition(getExpandedViewSize());
+ bbev.animate()
+ .x(restPoint.x)
+ .y(restPoint.y)
+ .scaleX(1f)
+ .scaleY(1f)
+ .setDuration(EXPANDED_VIEW_ANIMATE_POSITION_DURATION)
+ .setInterpolator(Interpolators.EMPHASIZED_DECELERATE)
+ .withStartAction(() -> bbev.setAnimating(true))
+ .withEndAction(() -> bbev.setAnimating(false))
+ .start();
+ }
+
+ /**
+ * Animates currently expanded bubble into the given {@link MagneticTarget}.
+ *
+ * @param target magnetic target to snap to
+ * @param endRunnable a runnable to run at the end of the animation
+ */
+ public void animateIntoTarget(MagneticTarget target, @Nullable Runnable endRunnable) {
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
+ Log.w(TAG, "Trying to snap the expanded view to target without a bubble");
+ return;
+ }
+ Point expandedViewCenter = getViewCenterOnScreen(bbev);
+
+ // Calculate the difference between the target's center coordinates and the object's.
+ // Animating the object's x/y properties by these values will center the object on top
+ // of the magnetic target.
+ float xDiff = target.getCenterOnScreen().x - expandedViewCenter.x;
+ float yDiff = target.getCenterOnScreen().y - expandedViewCenter.y;
+
+ // Calculate scale of expanded view so it fits inside the magnetic target
+ float bbevMaxSide = Math.max(bbev.getWidth(), bbev.getHeight());
+ float targetMaxSide = Math.max(target.getTargetView().getWidth(),
+ target.getTargetView().getHeight());
+ float scale = (targetMaxSide * EXPANDED_VIEW_IN_TARGET_SCALE) / bbevMaxSide;
+
+ bbev.animate()
+ .translationX(bbev.getTranslationX() + xDiff)
+ .translationY(bbev.getTranslationY() + yDiff)
+ .scaleX(scale)
+ .scaleY(scale)
+ .setDuration(EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION)
+ .setInterpolator(Interpolators.EMPHASIZED)
+ .withStartAction(() -> bbev.setAnimating(true))
+ .withEndAction(() -> {
+ bbev.setAnimating(false);
+ if (endRunnable != null) {
+ endRunnable.run();
+ }
+ })
+ .start();
+ }
+
+ /**
+ * Animate currently expanded view when it is released from dismiss view
+ */
+ public void animateUnstuckFromDismissView() {
+ BubbleBarExpandedView expandedView = getExpandedView();
+ if (expandedView == null) {
+ Log.w(TAG, "Trying to unsnap the expanded view from dismiss without a bubble");
+ return;
+ }
+ expandedView
+ .animate()
+ .scaleX(1f)
+ .scaleY(1f)
+ .setDuration(EXPANDED_VIEW_SNAP_TO_DISMISS_DURATION)
+ .setInterpolator(Interpolators.EMPHASIZED)
+ .withStartAction(() -> expandedView.setAnimating(true))
+ .withEndAction(() -> expandedView.setAnimating(false))
+ .start();
+ }
+
+ /**
* Cancel current animations
*/
public void cancelAnimations() {
PhysicsAnimator.getInstance(mExpandedViewContainerMatrix).cancel();
mExpandedViewAlphaAnimator.cancel();
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev != null) {
+ bbev.animate().cancel();
+ }
}
private @Nullable BubbleBarExpandedView getExpandedView() {
@@ -231,21 +355,42 @@ public class BubbleBarAnimationHelper {
return;
}
- boolean isOverflowExpanded = mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
- final int padding = mPositioner.getBubbleBarExpandedViewPadding();
- final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
- final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
+ final Size size = getExpandedViewSize();
+ Point position = getExpandedViewRestPosition(size);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) bbev.getLayoutParams();
- lp.width = width;
- lp.height = height;
+ lp.width = size.getWidth();
+ lp.height = size.getHeight();
bbev.setLayoutParams(lp);
+ bbev.setX(position.x);
+ bbev.setY(position.y);
+ bbev.updateLocation();
+ bbev.maybeShowOverflow();
+ }
+
+ private Point getExpandedViewRestPosition(Size size) {
+ final int padding = mPositioner.getBubbleBarExpandedViewPadding();
+ Point point = new Point();
if (mLayerView.isOnLeft()) {
- bbev.setX(mPositioner.getInsets().left + padding);
+ point.x = mPositioner.getInsets().left + padding;
} else {
- bbev.setX(mPositioner.getAvailableRect().width() - width - padding);
+ point.x = mPositioner.getAvailableRect().width() - size.getWidth() - padding;
}
- bbev.setY(mPositioner.getExpandedViewBottomForBubbleBar() - height);
- bbev.updateLocation();
- bbev.maybeShowOverflow();
+ point.y = mPositioner.getExpandedViewBottomForBubbleBar() - size.getHeight();
+ return point;
+ }
+
+ private Size getExpandedViewSize() {
+ boolean isOverflowExpanded = mExpandedBubble.getKey().equals(BubbleOverflow.KEY);
+ final int width = mPositioner.getExpandedViewWidthForBubbleBar(isOverflowExpanded);
+ final int height = mPositioner.getExpandedViewHeightForBubbleBar(isOverflowExpanded);
+ return new Size(width, height);
+ }
+
+ private Point getViewCenterOnScreen(View view) {
+ Point center = new Point();
+ int[] onScreenLocation = view.getLocationOnScreen();
+ center.x = (int) (onScreenLocation[0] + (view.getWidth() / 2f));
+ center.y = (int) (onScreenLocation[1] + (view.getHeight() / 2f));
+ return center;
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
index 4ea18f78f5b2..d21545079cc2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
@@ -16,70 +16,67 @@
package com.android.wm.shell.bubbles.bar
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.graphics.PointF
-import android.graphics.Rect
+import android.annotation.SuppressLint
import android.view.MotionEvent
import android.view.View
-import com.android.wm.shell.animation.Interpolators
import com.android.wm.shell.common.bubbles.DismissView
import com.android.wm.shell.common.bubbles.RelativeTouchListener
+import com.android.wm.shell.common.magnetictarget.MagnetizedObject
/** Controller for handling drag interactions with [BubbleBarExpandedView] */
+@SuppressLint("ClickableViewAccessibility")
class BubbleBarExpandedViewDragController(
private val expandedView: BubbleBarExpandedView,
private val dismissView: DismissView,
+ private val animationHelper: BubbleBarAnimationHelper,
private val onDismissed: () -> Unit
) {
+ var isStuckToDismiss: Boolean = false
+ private set
+
+ private var expandedViewInitialTranslationX = 0f
+ private var expandedViewInitialTranslationY = 0f
+ private val magnetizedExpandedView: MagnetizedObject<BubbleBarExpandedView> =
+ MagnetizedObject.magnetizeView(expandedView)
+ private val magnetizedDismissTarget: MagnetizedObject.MagneticTarget
+
init {
- expandedView.handleView.setOnTouchListener(HandleDragListener())
- }
+ magnetizedExpandedView.magnetListener = MagnetListener()
+ magnetizedExpandedView.animateStuckToTarget =
+ {
+ target: MagnetizedObject.MagneticTarget,
+ _: Float,
+ _: Float,
+ _: Boolean,
+ after: (() -> Unit)? ->
+ animationHelper.animateIntoTarget(target, after)
+ }
- private fun finishDrag(x: Float, y: Float, viewInitialX: Float, viewInitialY: Float) {
- val dismissCircleBounds = Rect().apply { dismissView.circle.getBoundsOnScreen(this) }
- if (dismissCircleBounds.contains(x.toInt(), y.toInt())) {
- onDismissed()
- } else {
- resetExpandedViewPosition(viewInitialX, viewInitialY)
- }
- dismissView.hide()
- }
+ magnetizedDismissTarget =
+ MagnetizedObject.MagneticTarget(dismissView.circle, dismissView.circle.width)
+ magnetizedExpandedView.addTarget(magnetizedDismissTarget)
- private fun resetExpandedViewPosition(initialX: Float, initialY: Float) {
- val listener =
- object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animation: Animator) {
- expandedView.isAnimating = true
- }
+ val dragMotionEventHandler = HandleDragListener()
- override fun onAnimationEnd(animation: Animator) {
- expandedView.isAnimating = false
- }
+ expandedView.handleView.setOnTouchListener { view, event ->
+ if (event.actionMasked == MotionEvent.ACTION_DOWN) {
+ expandedViewInitialTranslationX = expandedView.translationX
+ expandedViewInitialTranslationY = expandedView.translationY
}
- expandedView
- .animate()
- .translationX(initialX)
- .translationY(initialY)
- .setDuration(RESET_POSITION_ANIM_DURATION)
- .setInterpolator(Interpolators.EMPHASIZED_DECELERATE)
- .setListener(listener)
- .start()
+ val magnetConsumed = magnetizedExpandedView.maybeConsumeMotionEvent(event)
+ // Move events can be consumed by the magnetized object
+ if (event.actionMasked == MotionEvent.ACTION_MOVE && magnetConsumed) {
+ return@setOnTouchListener true
+ }
+ return@setOnTouchListener dragMotionEventHandler.onTouch(view, event) || magnetConsumed
+ }
}
private inner class HandleDragListener : RelativeTouchListener() {
-
- private val expandedViewRestPosition = PointF()
-
override fun onDown(v: View, ev: MotionEvent): Boolean {
// While animating, don't allow new touch events
- if (expandedView.isAnimating) {
- return false
- }
- expandedViewRestPosition.x = expandedView.translationX
- expandedViewRestPosition.y = expandedView.translationY
- return true
+ return !expandedView.isAnimating
}
override fun onMove(
@@ -90,8 +87,8 @@ class BubbleBarExpandedViewDragController(
dx: Float,
dy: Float
) {
- expandedView.translationX = expandedViewRestPosition.x + dx
- expandedView.translationY = expandedViewRestPosition.y + dy
+ expandedView.translationX = expandedViewInitialTranslationX + dx
+ expandedView.translationY = expandedViewInitialTranslationY + dy
dismissView.show()
}
@@ -105,16 +102,40 @@ class BubbleBarExpandedViewDragController(
velX: Float,
velY: Float
) {
- finishDrag(ev.rawX, ev.rawY, expandedViewRestPosition.x, expandedViewRestPosition.y)
+ finishDrag()
}
override fun onCancel(v: View, ev: MotionEvent, viewInitialX: Float, viewInitialY: Float) {
- resetExpandedViewPosition(expandedViewRestPosition.x, expandedViewRestPosition.y)
- dismissView.hide()
+ finishDrag()
+ }
+
+ private fun finishDrag() {
+ if (!isStuckToDismiss) {
+ animationHelper.animateToRestPosition()
+ dismissView.hide()
+ }
}
}
- companion object {
- const val RESET_POSITION_ANIM_DURATION = 300L
+ private inner class MagnetListener : MagnetizedObject.MagnetListener {
+ override fun onStuckToTarget(target: MagnetizedObject.MagneticTarget) {
+ isStuckToDismiss = true
+ }
+
+ override fun onUnstuckFromTarget(
+ target: MagnetizedObject.MagneticTarget,
+ velX: Float,
+ velY: Float,
+ wasFlungOut: Boolean
+ ) {
+ isStuckToDismiss = false
+ animationHelper.animateUnstuckFromDismissView()
+ }
+
+ override fun onReleasedInTarget(target: MagnetizedObject.MagneticTarget) {
+ onDismissed()
+ dismissView.hide()
+ }
}
}
+
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index bdb0e206e490..12114519d086 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.bubbles.bar;
import static com.android.wm.shell.animation.Interpolators.ALPHA_IN;
import static com.android.wm.shell.animation.Interpolators.ALPHA_OUT;
+import static com.android.wm.shell.bubbles.Bubbles.DISMISS_USER_GESTURE;
import android.annotation.Nullable;
import android.content.Context;
@@ -36,7 +37,6 @@ import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.bubbles.BubbleOverflow;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.BubbleViewProvider;
-import com.android.wm.shell.bubbles.Bubbles;
import com.android.wm.shell.bubbles.DeviceConfig;
import com.android.wm.shell.bubbles.DismissViewUtils;
import com.android.wm.shell.common.bubbles.DismissView;
@@ -206,10 +206,13 @@ public class BubbleBarLayerView extends FrameLayout
}
});
- mDragController = new BubbleBarExpandedViewDragController(mExpandedView, mDismissView,
+ mDragController = new BubbleBarExpandedViewDragController(
+ mExpandedView,
+ mDismissView,
+ mAnimationHelper,
() -> {
mBubbleController.dismissBubble(mExpandedBubble.getKey(),
- Bubbles.DISMISS_USER_GESTURE);
+ DISMISS_USER_GESTURE);
return Unit.INSTANCE;
});
@@ -241,7 +244,11 @@ public class BubbleBarLayerView extends FrameLayout
mIsExpanded = false;
final BubbleBarExpandedView viewToRemove = mExpandedView;
mEducationViewController.hideEducation(/* animated = */ true);
- mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
+ if (mDragController != null && mDragController.isStuckToDismiss()) {
+ mAnimationHelper.animateDismiss(() -> removeView(viewToRemove));
+ } else {
+ mAnimationHelper.animateCollapse(() -> removeView(viewToRemove));
+ }
mBubbleController.getSysuiProxy().onStackExpandChanged(false);
mExpandedView = null;
mDragController = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 0448d94669ce..0b8f60e44c7e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -96,7 +96,7 @@ public class PipScheduler {
@Nullable
private WindowContainerTransaction getExitPipViaExpandTransaction() {
- if (mPipTaskToken == null || mPinnedTaskLeash == null) {
+ if (mPipTaskToken == null) {
return null;
}
WindowContainerTransaction wct = new WindowContainerTransaction();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 6200ea583a48..48a0a46dccc1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -18,6 +18,7 @@ package com.android.wm.shell.pip2.phone;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_PIP;
import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP;
@@ -56,6 +57,8 @@ public class PipTransition extends PipTransitionController {
private IBinder mAutoEnterButtonNavTransition;
@Nullable
private IBinder mExitViaExpandTransition;
+ @Nullable
+ private IBinder mLegacyEnterTransition;
public PipTransition(
@NonNull ShellInit shellInit,
@@ -98,6 +101,9 @@ public class PipTransition extends PipTransitionController {
if (isAutoEnterInButtonNavigation(request)) {
mAutoEnterButtonNavTransition = transition;
return getEnterPipTransaction(transition, request);
+ } else if (isLegacyEnter(request)) {
+ mLegacyEnterTransition = transition;
+ return getEnterPipTransaction(transition, request);
}
return null;
}
@@ -108,6 +114,9 @@ public class PipTransition extends PipTransitionController {
if (isAutoEnterInButtonNavigation(request)) {
outWct.merge(getEnterPipTransaction(transition, request), true /* transfer */);
mAutoEnterButtonNavTransition = transition;
+ } else if (isLegacyEnter(request)) {
+ outWct.merge(getEnterPipTransaction(transition, request), true /* transfer */);
+ mLegacyEnterTransition = transition;
}
}
@@ -153,6 +162,10 @@ public class PipTransition extends PipTransitionController {
&& pipTask.pictureInPictureParams.isAutoEnterEnabled();
}
+ private boolean isLegacyEnter(@NonNull TransitionRequestInfo requestInfo) {
+ return requestInfo.getType() == TRANSIT_PIP;
+ }
+
@Override
public boolean startAnimation(@NonNull IBinder transition,
@NonNull TransitionInfo info,
@@ -161,29 +174,65 @@ public class PipTransition extends PipTransitionController {
@NonNull Transitions.TransitionFinishCallback finishCallback) {
if (transition == mAutoEnterButtonNavTransition) {
mAutoEnterButtonNavTransition = null;
- TransitionInfo.Change pipChange = getPipChange(info);
- if (pipChange == null) {
- return false;
- }
- mPipTaskToken = pipChange.getContainer();
-
- // cache the PiP task token and leash
- mPipScheduler.setPipTaskToken(mPipTaskToken);
- mPipScheduler.setPinnedTaskLeash(pipChange.getLeash());
-
- startTransaction.apply();
- finishCallback.onTransitionFinished(null);
- return true;
+ return startAutoEnterButtonNavAnimation(info, startTransaction, finishTransaction,
+ finishCallback);
+ } else if (transition == mLegacyEnterTransition) {
+ mLegacyEnterTransition = null;
+ return startLegacyEnterAnimation(info, startTransaction, finishTransaction,
+ finishCallback);
} else if (transition == mExitViaExpandTransition) {
mExitViaExpandTransition = null;
- startTransaction.apply();
- finishCallback.onTransitionFinished(null);
- onExitPip();
- return true;
+ return startExpandAnimation(info, startTransaction, finishTransaction, finishCallback);
}
return false;
}
+ private boolean startAutoEnterButtonNavAnimation(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ TransitionInfo.Change pipChange = getPipChange(info);
+ if (pipChange == null) {
+ return false;
+ }
+ mPipTaskToken = pipChange.getContainer();
+
+ // cache the PiP task token and leash
+ mPipScheduler.setPipTaskToken(mPipTaskToken);
+
+ startTransaction.apply();
+ finishCallback.onTransitionFinished(null);
+ return true;
+ }
+
+ private boolean startLegacyEnterAnimation(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ TransitionInfo.Change pipChange = getPipChange(info);
+ if (pipChange == null) {
+ return false;
+ }
+ mPipTaskToken = pipChange.getContainer();
+
+ // cache the PiP task token and leash
+ mPipScheduler.setPipTaskToken(mPipTaskToken);
+
+ startTransaction.apply();
+ finishCallback.onTransitionFinished(null);
+ return true;
+ }
+
+ private boolean startExpandAnimation(@NonNull TransitionInfo info,
+ @NonNull SurfaceControl.Transaction startTransaction,
+ @NonNull SurfaceControl.Transaction finishTransaction,
+ @NonNull Transitions.TransitionFinishCallback finishCallback) {
+ startTransaction.apply();
+ finishCallback.onTransitionFinished(null);
+ onExitPip();
+ return true;
+ }
+
@Nullable
private TransitionInfo.Change getPipChange(TransitionInfo info) {
for (TransitionInfo.Change change : info.getChanges()) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingConstants.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingConstants.java
index d8475b3f22af..ca0cad759a08 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingConstants.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidAudioRoutingConstants.java
@@ -39,21 +39,22 @@ public final class HearingAidAudioRoutingConstants {
public static final int[] MEDIA_ROUTING_ATTRIBUTES = new int[] {
// Stands for STRATEGY_MEDIA, including USAGE_GAME, USAGE_ASSISTANT,
// USAGE_ASSISTANCE_NAVIGATION_GUIDANCE, USAGE_ASSISTANCE_SONIFICATION
- AudioAttributes.USAGE_MEDIA
+ AudioAttributes.USAGE_MEDIA,
+ // Stands for STRATEGY_ACCESSIBILITY
+ AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
+ // Stands for STRATEGY_DTMF
+ AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING,
};
- public static final int[] RINGTONE_ROUTING_ATTRIBUTE = new int[] {
+ public static final int[] RINGTONE_ROUTING_ATTRIBUTES = new int[] {
// Stands for STRATEGY_SONIFICATION, including USAGE_ALARM
AudioAttributes.USAGE_NOTIFICATION_RINGTONE
};
- public static final int[] SYSTEM_SOUNDS_ROUTING_ATTRIBUTES = new int[] {
+ public static final int[] NOTIFICATION_ROUTING_ATTRIBUTES = new int[] {
// Stands for STRATEGY_SONIFICATION_RESPECTFUL, including USAGE_NOTIFICATION_EVENT
AudioAttributes.USAGE_NOTIFICATION,
- // Stands for STRATEGY_ACCESSIBILITY
- AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
- // Stands for STRATEGY_DTMF
- AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING,
+
};
@Retention(RetentionPolicy.SOURCE)
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index 111a2c1a07ea..3a15b7108e3f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -26,6 +26,7 @@ import android.media.AudioDeviceAttributes;
import android.media.audiopolicy.AudioProductStrategy;
import android.os.ParcelUuid;
import android.provider.Settings;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -42,11 +43,13 @@ public class HearingAidDeviceManager {
private static final boolean DEBUG = BluetoothUtils.D;
private final ContentResolver mContentResolver;
+ private final Context mContext;
private final LocalBluetoothManager mBtManager;
private final List<CachedBluetoothDevice> mCachedDevices;
private final HearingAidAudioRoutingHelper mRoutingHelper;
HearingAidDeviceManager(Context context, LocalBluetoothManager localBtManager,
List<CachedBluetoothDevice> CachedDevices) {
+ mContext = context;
mContentResolver = context.getContentResolver();
mBtManager = localBtManager;
mCachedDevices = CachedDevices;
@@ -56,6 +59,7 @@ public class HearingAidDeviceManager {
@VisibleForTesting
HearingAidDeviceManager(Context context, LocalBluetoothManager localBtManager,
List<CachedBluetoothDevice> cachedDevices, HearingAidAudioRoutingHelper routingHelper) {
+ mContext = context;
mContentResolver = context.getContentResolver();
mBtManager = localBtManager;
mCachedDevices = cachedDevices;
@@ -285,11 +289,13 @@ public class HearingAidDeviceManager {
}
void onActiveDeviceChanged(CachedBluetoothDevice device) {
- if (device.isActiveDevice(BluetoothProfile.HEARING_AID) || device.isActiveDevice(
- BluetoothProfile.LE_AUDIO)) {
- setAudioRoutingConfig(device);
- } else {
- clearAudioRoutingConfig();
+ if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_AUDIO_ROUTING)) {
+ if (device.isActiveDevice(BluetoothProfile.HEARING_AID) || device.isActiveDevice(
+ BluetoothProfile.LE_AUDIO)) {
+ setAudioRoutingConfig(device);
+ } else {
+ clearAudioRoutingConfig();
+ }
}
}
@@ -312,7 +318,7 @@ public class HearingAidDeviceManager {
Settings.Secure.HEARING_AID_RINGTONE_ROUTING,
HearingAidAudioRoutingConstants.RoutingValue.AUTO);
final int systemSoundsRoutingValue = Settings.Secure.getInt(mContentResolver,
- Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
+ Settings.Secure.HEARING_AID_NOTIFICATION_ROUTING,
HearingAidAudioRoutingConstants.RoutingValue.AUTO);
setPreferredDeviceRoutingStrategies(
@@ -322,10 +328,10 @@ public class HearingAidDeviceManager {
HearingAidAudioRoutingConstants.MEDIA_ROUTING_ATTRIBUTES,
hearingDeviceAttributes, mediaRoutingValue);
setPreferredDeviceRoutingStrategies(
- HearingAidAudioRoutingConstants.RINGTONE_ROUTING_ATTRIBUTE,
+ HearingAidAudioRoutingConstants.RINGTONE_ROUTING_ATTRIBUTES,
hearingDeviceAttributes, ringtoneRoutingValue);
setPreferredDeviceRoutingStrategies(
- HearingAidAudioRoutingConstants.SYSTEM_SOUNDS_ROUTING_ATTRIBUTES,
+ HearingAidAudioRoutingConstants.NOTIFICATION_ROUTING_ATTRIBUTES,
hearingDeviceAttributes, systemSoundsRoutingValue);
}
@@ -338,10 +344,10 @@ public class HearingAidDeviceManager {
HearingAidAudioRoutingConstants.MEDIA_ROUTING_ATTRIBUTES,
/* hearingDevice = */ null, HearingAidAudioRoutingConstants.RoutingValue.AUTO);
setPreferredDeviceRoutingStrategies(
- HearingAidAudioRoutingConstants.RINGTONE_ROUTING_ATTRIBUTE,
+ HearingAidAudioRoutingConstants.RINGTONE_ROUTING_ATTRIBUTES,
/* hearingDevice = */ null, HearingAidAudioRoutingConstants.RoutingValue.AUTO);
setPreferredDeviceRoutingStrategies(
- HearingAidAudioRoutingConstants.SYSTEM_SOUNDS_ROUTING_ATTRIBUTES,
+ HearingAidAudioRoutingConstants.NOTIFICATION_ROUTING_ATTRIBUTES,
/* hearingDevice = */ null, HearingAidAudioRoutingConstants.RoutingValue.AUTO);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index ea10944be0e9..24fd06e51418 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -42,6 +42,7 @@ import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.audiopolicy.AudioProductStrategy;
import android.os.Parcel;
+import android.util.FeatureFlagUtils;
import androidx.test.core.app.ApplicationProvider;
@@ -109,6 +110,7 @@ public class HearingAidDeviceManagerTest {
@Before
public void setUp() {
+ FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true);
when(mDevice1.getAddress()).thenReturn(DEVICE_ADDRESS_1);
when(mDevice2.getAddress()).thenReturn(DEVICE_ADDRESS_2);
when(mDevice1.getName()).thenReturn(DEVICE_NAME_1);
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index ec456e09a3c1..5004f251cfd3 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -74,6 +74,7 @@ public class SecureSettings {
Settings.Secure.TTS_DEFAULT_LOCALE,
Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS,
+ Settings.Secure.ACCESSIBILITY_STICKY_KEYS,
Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, // moved to global
Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, // moved to global
Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, // moved to global
@@ -246,7 +247,7 @@ public class SecureSettings {
Settings.Secure.HEARING_AID_RINGTONE_ROUTING,
Settings.Secure.HEARING_AID_CALL_ROUTING,
Settings.Secure.HEARING_AID_MEDIA_ROUTING,
- Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
+ Settings.Secure.HEARING_AID_NOTIFICATION_ROUTING,
Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
Settings.Secure.SEARCH_PRESS_HOLD_NAV_HANDLE_ENABLED,
Settings.Secure.SEARCH_LONG_PRESS_HOME_ENABLED,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 5ad14ceb31cf..0b0e182746e5 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -120,6 +120,7 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.TTS_DEFAULT_LOCALE, TTS_LIST_VALIDATOR);
VALIDATORS.put(Secure.SHOW_IME_WITH_HARD_KEYBOARD, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_BOUNCE_KEYS, ANY_INTEGER_VALIDATOR);
+ VALIDATORS.put(Secure.ACCESSIBILITY_STICKY_KEYS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, NON_NEGATIVE_INTEGER_VALIDATOR);
@@ -395,7 +396,7 @@ public class SecureSettingsValidators {
new DiscreteValueValidator(new String[] {"0", "1", "2"}));
VALIDATORS.put(Secure.HEARING_AID_MEDIA_ROUTING,
new DiscreteValueValidator(new String[] {"0", "1", "2"}));
- VALIDATORS.put(Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
+ VALIDATORS.put(Secure.HEARING_AID_NOTIFICATION_ROUTING,
new DiscreteValueValidator(new String[] {"0", "1", "2"}));
VALIDATORS.put(Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_EDGE_HAPTIC_ENABLED,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 5afcd5db1b5f..1670a705f939 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1866,8 +1866,8 @@ class SettingsProtoDumpUtil {
Settings.Secure.HEARING_AID_MEDIA_ROUTING,
SecureSettingsProto.Accessibility.HEARING_AID_MEDIA_ROUTING);
dumpSetting(s, p,
- Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING,
- SecureSettingsProto.Accessibility.HEARING_AID_SYSTEM_SOUNDS_ROUTING);
+ Settings.Secure.HEARING_AID_NOTIFICATION_ROUTING,
+ SecureSettingsProto.Accessibility.HEARING_AID_NOTIFICATION_ROUTING);
dumpSetting(s, p,
Settings.Secure.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED,
SecureSettingsProto.Accessibility.ACCESSIBILITY_FONT_SCALING_HAS_BEEN_CHANGED);
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index f10ac1bf1e0a..cc5dfc66cb74 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -277,6 +277,7 @@ android_library {
"SystemUIPluginLib",
"SystemUISharedLib",
"SystemUICustomizationLib",
+ "SystemUICustomizationTestUtils",
"SystemUI-statsd",
"SettingsLib",
"com_android_systemui_flags_lib",
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index facb244a5489..21ca613bca34 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -160,6 +160,15 @@ flag {
}
flag {
+ name: "edge_back_gesture_handler_thread"
+ namespace: "systemui"
+ description: "Moves the EdgeBackGestureHandler window, which is used for rendering the back "
+ "arrow, to a separate thread. Previously, the EdgeBackGestureHandler window would share "
+ "the main thread with the rest of System UI."
+ bug: "304583132"
+}
+
+flag {
name: "new_aod_transition"
namespace: "systemui"
description: "New LOCKSCREEN <=> AOD transition"
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index d83f3aae1ace..249b3e14ec72 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -74,7 +74,7 @@ fun CommunalContainer(
) {
val currentScene: SceneKey by
viewModel.currentScene
- .transform<CommunalSceneKey, SceneKey> { value -> value.toTransitionSceneKey() }
+ .transform { value -> emit(value.toTransitionSceneKey()) }
.collectAsState(TransitionSceneKey.Blank)
val sceneTransitionLayoutState = remember { SceneTransitionLayoutState(currentScene) }
// Don't show hub mode UI if keyguard is present. This is important since we're in the shade,
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepository.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepository.kt
new file mode 100644
index 000000000000..0b7c3f987db2
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/notifications/data/repository/NotificationSettingsRepository.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.notifications.data.repository
+
+import android.provider.Settings
+import com.android.systemui.shared.notifications.shared.model.NotificationSettingsModel
+import com.android.systemui.shared.settings.data.repository.SecureSettingsRepository
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.shareIn
+import kotlinx.coroutines.withContext
+
+/** Provides access to state related to notifications. */
+class NotificationSettingsRepository(
+ scope: CoroutineScope,
+ private val backgroundDispatcher: CoroutineDispatcher,
+ private val secureSettingsRepository: SecureSettingsRepository,
+) {
+ /** The current state of the notification setting. */
+ val settings: SharedFlow<NotificationSettingsModel> =
+ secureSettingsRepository
+ .intSetting(
+ name = Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ )
+ .map { lockScreenShowNotificationsInt ->
+ NotificationSettingsModel(
+ isShowNotificationsOnLockScreenEnabled = lockScreenShowNotificationsInt == 1,
+ )
+ }
+ .shareIn(
+ scope = scope,
+ started = SharingStarted.WhileSubscribed(),
+ replay = 1,
+ )
+
+ suspend fun getSettings(): NotificationSettingsModel {
+ return withContext(backgroundDispatcher) {
+ NotificationSettingsModel(
+ isShowNotificationsOnLockScreenEnabled =
+ secureSettingsRepository.get(
+ name = Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ defaultValue = 0,
+ ) == 1
+ )
+ }
+ }
+
+ suspend fun setSettings(model: NotificationSettingsModel) {
+ withContext(backgroundDispatcher) {
+ secureSettingsRepository.set(
+ name = Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
+ value = if (model.isShowNotificationsOnLockScreenEnabled) 1 else 0,
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/notifications/domain/interactor/NotificationSettingsInteractor.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/notifications/domain/interactor/NotificationSettingsInteractor.kt
new file mode 100644
index 000000000000..21f3acaf15ff
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/notifications/domain/interactor/NotificationSettingsInteractor.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.notifications.domain.interactor
+
+import com.android.systemui.shared.notifications.data.repository.NotificationSettingsRepository
+import com.android.systemui.shared.notifications.shared.model.NotificationSettingsModel
+import kotlinx.coroutines.flow.Flow
+
+/** Encapsulates business logic for interacting with notification settings. */
+class NotificationSettingsInteractor(
+ private val repository: NotificationSettingsRepository,
+) {
+ /** The current state of the notification setting. */
+ val settings: Flow<NotificationSettingsModel> = repository.settings
+
+ /** Toggles the setting to show or hide notifications on the lock screen. */
+ suspend fun toggleShowNotificationsOnLockScreenEnabled() {
+ val currentModel = repository.getSettings()
+ setSettings(
+ currentModel.copy(
+ isShowNotificationsOnLockScreenEnabled =
+ !currentModel.isShowNotificationsOnLockScreenEnabled,
+ )
+ )
+ }
+
+ suspend fun setSettings(model: NotificationSettingsModel) {
+ repository.setSettings(model)
+ }
+
+ suspend fun getSettings(): NotificationSettingsModel {
+ return repository.getSettings()
+ }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/notifications/shared/model/NotificationSettingsModel.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/notifications/shared/model/NotificationSettingsModel.kt
new file mode 100644
index 000000000000..7e35360e30ff
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/notifications/shared/model/NotificationSettingsModel.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.shared.notifications.shared.model
+
+/** Models notification settings. */
+data class NotificationSettingsModel(
+ /** Whether notifications are shown on the lock screen. */
+ val isShowNotificationsOnLockScreenEnabled: Boolean = false,
+)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/settings/data/repository/SecureSettingsRepository.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/settings/data/repository/SecureSettingsRepository.kt
new file mode 100644
index 000000000000..7ef16a8a4b23
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/settings/data/repository/SecureSettingsRepository.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.settings.data.repository
+
+import android.content.ContentResolver
+import android.database.ContentObserver
+import android.provider.Settings
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.withContext
+
+/** Defines interface for classes that can provide access to data from [Settings.Secure]. */
+interface SecureSettingsRepository {
+
+ /** Returns a [Flow] tracking the value of a setting as an [Int]. */
+ fun intSetting(
+ name: String,
+ defaultValue: Int = 0,
+ ): Flow<Int>
+
+ /** Updates the value of the setting with the given name. */
+ suspend fun set(
+ name: String,
+ value: Int,
+ )
+
+ suspend fun get(
+ name: String,
+ defaultValue: Int = 0,
+ ): Int
+}
+
+class SecureSettingsRepositoryImpl(
+ private val contentResolver: ContentResolver,
+ private val backgroundDispatcher: CoroutineDispatcher,
+) : SecureSettingsRepository {
+
+ override fun intSetting(
+ name: String,
+ defaultValue: Int,
+ ): Flow<Int> {
+ return callbackFlow {
+ val observer =
+ object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean) {
+ trySend(Unit)
+ }
+ }
+
+ contentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(name),
+ /* notifyForDescendants= */ false,
+ observer,
+ )
+ send(Unit)
+
+ awaitClose { contentResolver.unregisterContentObserver(observer) }
+ }
+ .map { Settings.Secure.getInt(contentResolver, name, defaultValue) }
+ // The above work is done on the background thread (which is important for accessing
+ // settings through the content resolver).
+ .flowOn(backgroundDispatcher)
+ }
+
+ override suspend fun set(name: String, value: Int) {
+ withContext(backgroundDispatcher) {
+ Settings.Secure.putInt(
+ contentResolver,
+ name,
+ value,
+ )
+ }
+ }
+
+ override suspend fun get(name: String, defaultValue: Int): Int {
+ return withContext(backgroundDispatcher) {
+ Settings.Secure.getInt(
+ contentResolver,
+ name,
+ defaultValue,
+ )
+ }
+ }
+}
diff --git a/packages/SystemUI/customization/tests/utils/Android.bp b/packages/SystemUI/customization/tests/utils/Android.bp
new file mode 100644
index 000000000000..6db141030cce
--- /dev/null
+++ b/packages/SystemUI/customization/tests/utils/Android.bp
@@ -0,0 +1,33 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_packages_SystemUI_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
+}
+
+java_library {
+ name: "SystemUICustomizationTestUtils",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "SystemUICustomizationLib",
+ ],
+}
diff --git a/packages/SystemUI/customization/tests/utils/src/com/android/systemui/shared/settings/data/repository/FakeSecureSettingsRepository.kt b/packages/SystemUI/customization/tests/utils/src/com/android/systemui/shared/settings/data/repository/FakeSecureSettingsRepository.kt
new file mode 100644
index 000000000000..1c86a0745751
--- /dev/null
+++ b/packages/SystemUI/customization/tests/utils/src/com/android/systemui/shared/settings/data/repository/FakeSecureSettingsRepository.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.settings.data.repository
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.map
+
+class FakeSecureSettingsRepository : SecureSettingsRepository {
+
+ private val settings = MutableStateFlow<Map<String, String>>(mutableMapOf())
+
+ override fun intSetting(name: String, defaultValue: Int): Flow<Int> {
+ return settings.map { it.getOrDefault(name, defaultValue.toString()) }.map { it.toInt() }
+ }
+
+ override suspend fun set(name: String, value: Int) {
+ settings.value = settings.value.toMutableMap().apply { this[name] = value.toString() }
+ }
+
+ override suspend fun get(name: String, defaultValue: Int): Int {
+ return settings.value[name]?.toInt() ?: defaultValue
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorInversionRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorInversionRepositoryImplTest.kt
new file mode 100644
index 000000000000..3f05fef3c141
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/accessibility/data/repository/ColorInversionRepositoryImplTest.kt
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.data.repository
+
+import android.os.UserHandle
+import android.provider.Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorInversionRepositoryImplTest : SysuiTestCase() {
+
+ private val testDispatcher = StandardTestDispatcher()
+ private val scope = TestScope(testDispatcher)
+ private val settings: FakeSettings = FakeSettings()
+
+ private lateinit var underTest: ColorInversionRepository
+
+ @Before
+ fun setUp() {
+ underTest =
+ ColorInversionRepositoryImpl(
+ testDispatcher,
+ settings,
+ )
+ }
+
+ @Test
+ fun isEnabled_initiallyGetsSettingsValue() =
+ scope.runTest {
+ settings.putIntForUser(SETTING_NAME, 1, TEST_USER_1.identifier)
+
+ underTest =
+ ColorInversionRepositoryImpl(
+ testDispatcher,
+ settings,
+ )
+
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+ runCurrent()
+
+ val actualValue: Boolean = underTest.isEnabled(TEST_USER_1).first()
+ assertThat(actualValue).isTrue()
+ }
+
+ @Test
+ fun isEnabled_settingUpdated_valueUpdated() =
+ scope.runTest {
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+
+ settings.putIntForUser(SETTING_NAME, DISABLED, TEST_USER_1.identifier)
+ runCurrent()
+ assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+
+ settings.putIntForUser(SETTING_NAME, ENABLED, TEST_USER_1.identifier)
+ runCurrent()
+ assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue()
+
+ settings.putIntForUser(SETTING_NAME, DISABLED, TEST_USER_1.identifier)
+ runCurrent()
+ assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+ }
+
+ @Test
+ fun isEnabled_settingForUserOneOnly_valueUpdatedForUserOneOnly() =
+ scope.runTest {
+ underTest.isEnabled(TEST_USER_1).launchIn(backgroundScope)
+ settings.putIntForUser(SETTING_NAME, DISABLED, TEST_USER_1.identifier)
+ underTest.isEnabled(TEST_USER_2).launchIn(backgroundScope)
+ settings.putIntForUser(SETTING_NAME, DISABLED, TEST_USER_2.identifier)
+
+ runCurrent()
+ assertThat(underTest.isEnabled(TEST_USER_1).first()).isFalse()
+ assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse()
+
+ settings.putIntForUser(SETTING_NAME, ENABLED, TEST_USER_1.identifier)
+ runCurrent()
+ assertThat(underTest.isEnabled(TEST_USER_1).first()).isTrue()
+ assertThat(underTest.isEnabled(TEST_USER_2).first()).isFalse()
+ }
+
+ @Test
+ fun setEnabled() =
+ scope.runTest {
+ val success = underTest.setIsEnabled(true, TEST_USER_1)
+ runCurrent()
+ assertThat(success).isTrue()
+
+ val actualValue = settings.getIntForUser(SETTING_NAME, TEST_USER_1.identifier)
+ assertThat(actualValue).isEqualTo(ENABLED)
+ }
+
+ @Test
+ fun setDisabled() =
+ scope.runTest {
+ val success = underTest.setIsEnabled(false, TEST_USER_1)
+ runCurrent()
+ assertThat(success).isTrue()
+
+ val actualValue = settings.getIntForUser(SETTING_NAME, TEST_USER_1.identifier)
+ assertThat(actualValue).isEqualTo(DISABLED)
+ }
+
+ companion object {
+ private const val SETTING_NAME = ACCESSIBILITY_DISPLAY_INVERSION_ENABLED
+ private const val DISABLED = 0
+ private const val ENABLED = 1
+ private val TEST_USER_1 = UserHandle.of(1)!!
+ private val TEST_USER_2 = UserHandle.of(2)!!
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapperTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapperTest.kt
new file mode 100644
index 000000000000..f3c3579966fd
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapperTest.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.inversion.domain
+
+import android.graphics.drawable.TestStubDrawable
+import android.widget.Switch
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.tileimpl.SubtitleArrayMapping
+import com.android.systemui.qs.tiles.impl.custom.QSTileStateSubject
+import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel
+import com.android.systemui.qs.tiles.impl.inversion.qsColorInversionTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorInversionTileMapperTest : SysuiTestCase() {
+ private val kosmos = Kosmos()
+ private val colorInversionTileConfig = kosmos.qsColorInversionTileConfig
+ private val subtitleArrayId =
+ SubtitleArrayMapping.getSubtitleId(colorInversionTileConfig.tileSpec.spec)
+ private val subtitleArray = context.resources.getStringArray(subtitleArrayId)
+ // Using lazy (versus =) to make sure we override the right context -- see b/311612168
+ private val mapper by lazy {
+ ColorInversionTileMapper(
+ context.orCreateTestableResources
+ .apply {
+ addOverride(R.drawable.qs_invert_colors_icon_off, TestStubDrawable())
+ addOverride(R.drawable.qs_invert_colors_icon_on, TestStubDrawable())
+ }
+ .resources,
+ context.theme
+ )
+ }
+
+ @Test
+ fun disabledModel() {
+ val inputModel = ColorInversionTileModel(false)
+
+ val outputState = mapper.map(colorInversionTileConfig, inputModel)
+
+ val expectedState =
+ createColorInversionTileState(
+ QSTileState.ActivationState.INACTIVE,
+ subtitleArray[1],
+ R.drawable.qs_invert_colors_icon_off
+ )
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ @Test
+ fun enabledModel() {
+ val inputModel = ColorInversionTileModel(true)
+
+ val outputState = mapper.map(colorInversionTileConfig, inputModel)
+
+ val expectedState =
+ createColorInversionTileState(
+ QSTileState.ActivationState.ACTIVE,
+ subtitleArray[2],
+ R.drawable.qs_invert_colors_icon_on
+ )
+ QSTileStateSubject.assertThat(outputState).isEqualTo(expectedState)
+ }
+
+ private fun createColorInversionTileState(
+ activationState: QSTileState.ActivationState,
+ secondaryLabel: String,
+ iconRes: Int,
+ ): QSTileState {
+ val label = context.getString(R.string.quick_settings_inversion_label)
+ return QSTileState(
+ { Icon.Loaded(context.getDrawable(iconRes)!!, null) },
+ label,
+ activationState,
+ secondaryLabel,
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK),
+ label,
+ null,
+ QSTileState.SideViewIcon.None,
+ QSTileState.EnabledState.ENABLED,
+ Switch::class.qualifiedName
+ )
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt
new file mode 100644
index 000000000000..24c7bfb2d324
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractorTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.inversion.domain.interactor
+
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeColorInversionRepository
+import com.android.systemui.coroutines.collectValues
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.toCollection
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorInversionTileDataInteractorTest : SysuiTestCase() {
+
+ private val colorInversionRepository = FakeColorInversionRepository()
+ private val underTest: ColorInversionTileDataInteractor =
+ ColorInversionTileDataInteractor(colorInversionRepository)
+
+ @Test
+ fun alwaysAvailable() = runTest {
+ val availability = underTest.availability(TEST_USER).toCollection(mutableListOf())
+
+ assertThat(availability).hasSize(1)
+ assertThat(availability.last()).isTrue()
+ }
+
+ @Test
+ fun dataMatchesTheRepository() = runTest {
+ val dataList: List<ColorInversionTileModel> by
+ collectValues(underTest.tileData(TEST_USER, flowOf(DataUpdateTrigger.InitialRequest)))
+ runCurrent()
+
+ colorInversionRepository.setIsEnabled(true, TEST_USER)
+ runCurrent()
+
+ colorInversionRepository.setIsEnabled(false, TEST_USER)
+ runCurrent()
+
+ assertThat(dataList).hasSize(3)
+ assertThat(dataList.map { it.isEnabled }).isEqualTo(listOf(false, true, false))
+ }
+
+ private companion object {
+ val TEST_USER = UserHandle.of(1)!!
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
new file mode 100644
index 000000000000..99bae18d43d4
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractorTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.inversion.domain.interactor
+
+import android.os.UserHandle
+import android.provider.Settings
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.accessibility.data.repository.FakeColorInversionRepository
+import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
+import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx
+import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ColorInversionUserActionInteractorTest : SysuiTestCase() {
+
+ private val testUser = UserHandle.CURRENT
+ private val repository = FakeColorInversionRepository()
+ private val inputHandler = FakeQSTileIntentUserInputHandler()
+
+ private val underTest =
+ ColorInversionUserActionInteractor(
+ repository,
+ inputHandler,
+ )
+
+ @Test
+ fun handleClickWhenEnabled() = runTest {
+ val wasEnabled = true
+ repository.setIsEnabled(wasEnabled, testUser)
+
+ underTest.handleInput(QSTileInputTestKtx.click(ColorInversionTileModel(wasEnabled)))
+
+ assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleClickWhenDisabled() = runTest {
+ val wasEnabled = false
+ repository.setIsEnabled(wasEnabled, testUser)
+
+ underTest.handleInput(QSTileInputTestKtx.click(ColorInversionTileModel(wasEnabled)))
+
+ assertThat(repository.isEnabled(testUser).value).isEqualTo(!wasEnabled)
+ }
+
+ @Test
+ fun handleLongClickWhenDisabled() = runTest {
+ val enabled = false
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(ColorInversionTileModel(enabled)))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_INVERSION_SETTINGS)
+ }
+ }
+
+ @Test
+ fun handleLongClickWhenEnabled() = runTest {
+ val enabled = true
+
+ underTest.handleInput(QSTileInputTestKtx.longClick(ColorInversionTileModel(enabled)))
+
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(Settings.ACTION_COLOR_INVERSION_SETTINGS)
+ }
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/LockscreenTargetFilterTest.kt
index 886c61ae29dd..bf33010a055b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/LockscreenAndDreamTargetFilterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/smartspace/LockscreenTargetFilterTest.kt
@@ -27,7 +27,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.settings.UserTracker
-import com.android.systemui.smartspace.filters.LockscreenAndDreamTargetFilter
+import com.android.systemui.smartspace.filters.LockscreenTargetFilter
import com.android.systemui.util.concurrency.Execution
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
@@ -52,55 +52,52 @@ import org.mockito.MockitoAnnotations
@SmallTest
@TestableLooper.RunWithLooper
@RunWith(AndroidJUnit4::class)
-class LockscreenAndDreamTargetFilterTest : SysuiTestCase() {
- @Mock
- private lateinit var secureSettings: SecureSettings
+class LockscreenTargetFilterTest : SysuiTestCase() {
+ @Mock private lateinit var secureSettings: SecureSettings
- @Mock
- private lateinit var userTracker: UserTracker
+ @Mock private lateinit var userTracker: UserTracker
- @Mock
- private lateinit var execution: Execution
+ @Mock private lateinit var execution: Execution
- @Mock
- private lateinit var handler: Handler
+ @Mock private lateinit var handler: Handler
- @Mock
- private lateinit var contentResolver: ContentResolver
+ @Mock private lateinit var contentResolver: ContentResolver
- @Mock
- private lateinit var uiExecution: Executor
+ @Mock private lateinit var uiExecution: Executor
- @Mock
- private lateinit var userHandle: UserHandle
+ @Mock private lateinit var userHandle: UserHandle
- @Mock
- private lateinit var listener: SmartspaceTargetFilter.Listener
+ @Mock private lateinit var listener: SmartspaceTargetFilter.Listener
- @Mock
- private lateinit var lockScreenAllowPrivateNotificationsUri: Uri
+ @Mock private lateinit var lockScreenAllowPrivateNotificationsUri: Uri
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
`when`(userTracker.userHandle).thenReturn(userHandle)
- `when`(secureSettings
- .getUriFor(eq(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS)))
- .thenReturn(lockScreenAllowPrivateNotificationsUri)
+ `when`(
+ secureSettings.getUriFor(
+ eq(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS)
+ )
+ )
+ .thenReturn(lockScreenAllowPrivateNotificationsUri)
}
- /**
- * Ensures {@link Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS} is
- * tracked.
- */
+ /** Ensures {@link Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS} is tracked. */
@Test
fun testLockscreenAllowPrivateNotifications() {
var setting = Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
- `when`(secureSettings
- .getIntForUser(eq(setting) ?: setting, anyInt(), anyInt()))
- .thenReturn(0)
- var filter = LockscreenAndDreamTargetFilter(secureSettings, userTracker, execution, handler,
- contentResolver, uiExecution)
+ `when`(secureSettings.getIntForUser(eq(setting) ?: setting, anyInt(), anyInt()))
+ .thenReturn(0)
+ var filter =
+ LockscreenTargetFilter(
+ secureSettings,
+ userTracker,
+ execution,
+ handler,
+ contentResolver,
+ uiExecution
+ )
filter.addListener(listener)
var smartspaceTarget = mock(SmartspaceTarget::class.java)
@@ -110,12 +107,16 @@ class LockscreenAndDreamTargetFilterTest : SysuiTestCase() {
var settingCaptor = ArgumentCaptor.forClass(ContentObserver::class.java)
- verify(contentResolver).registerContentObserver(eq(lockScreenAllowPrivateNotificationsUri),
- anyBoolean(), settingCaptor.capture(), anyInt())
+ verify(contentResolver)
+ .registerContentObserver(
+ eq(lockScreenAllowPrivateNotificationsUri),
+ anyBoolean(),
+ settingCaptor.capture(),
+ anyInt()
+ )
- `when`(secureSettings
- .getIntForUser(eq(setting) ?: setting, anyInt(), anyInt()))
- .thenReturn(1)
+ `when`(secureSettings.getIntForUser(eq(setting) ?: setting, anyInt(), anyInt()))
+ .thenReturn(1)
clearInvocations(listener)
settingCaptor.value.onChange(false, mock(Uri::class.java))
@@ -123,23 +124,28 @@ class LockscreenAndDreamTargetFilterTest : SysuiTestCase() {
assertThat(filter.filterSmartspaceTarget(smartspaceTarget)).isTrue()
}
- /**
- * Ensures user switches are tracked.
- */
+ /** Ensures user switches are tracked. */
@Test
fun testUserSwitchCallback() {
var setting = Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
- `when`(secureSettings
- .getIntForUser(eq(setting) ?: setting, anyInt(), anyInt()))
- .thenReturn(0)
- var filter = LockscreenAndDreamTargetFilter(secureSettings, userTracker, execution, handler,
- contentResolver, uiExecution)
+ `when`(secureSettings.getIntForUser(eq(setting) ?: setting, anyInt(), anyInt()))
+ .thenReturn(0)
+ var filter =
+ LockscreenTargetFilter(
+ secureSettings,
+ userTracker,
+ execution,
+ handler,
+ contentResolver,
+ uiExecution
+ )
filter.addListener(listener)
- var userTrackerCallback = withArgCaptor<UserTracker.Callback> {
- verify(userTracker).addCallback(capture(), any())
- }
+ var userTrackerCallback =
+ withArgCaptor<UserTracker.Callback> {
+ verify(userTracker).addCallback(capture(), any())
+ }
clearInvocations(listener)
userTrackerCallback.onUserChanged(0, context)
diff --git a/packages/SystemUI/proguard_common.flags b/packages/SystemUI/proguard_common.flags
index 21b019eacdcc..f9546c46e915 100644
--- a/packages/SystemUI/proguard_common.flags
+++ b/packages/SystemUI/proguard_common.flags
@@ -38,6 +38,11 @@
-keepnames class com.android.internal.protolog.** { *; }
-keepnames class android.hardware.common.** { *; }
+# TODO(b/316553881): Statically linking flags into SystemUI and bootclasspath might not be a
+# good idea in the first place
+-keepnames class com.android.window.flags.Flags { public *; }
+
+
# Allows proguard to make private and protected methods and fields public as
# part of optimization. This lets proguard inline trivial getter/setter methods.
-allowaccessmodification
diff --git a/packages/SystemUI/res/layout/bluetooth_device_item.xml b/packages/SystemUI/res/layout/bluetooth_device_item.xml
index 4336ccc70c33..4535f67fa7f9 100644
--- a/packages/SystemUI/res/layout/bluetooth_device_item.xml
+++ b/packages/SystemUI/res/layout/bluetooth_device_item.xml
@@ -41,7 +41,7 @@
android:textDirection="locale"
android:textAlignment="gravity"
android:paddingStart="20dp"
- android:paddingTop="10dp"
+ android:paddingTop="15dp"
android:maxLines="1"
android:ellipsize="end"
app:layout_constraintTop_toTopOf="parent"
@@ -56,7 +56,7 @@
android:id="@+id/bluetooth_device_summary"
style="@style/BluetoothTileDialog.DeviceSummary"
android:paddingStart="20dp"
- android:paddingBottom="10dp"
+ android:paddingBottom="15dp"
android:maxLines="1"
android:ellipsize="end"
app:layout_constraintTop_toBottomOf="@+id/bluetooth_device_name"
diff --git a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
index 50241cdca8b5..0534c6ee466f 100644
--- a/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
+++ b/packages/SystemUI/res/layout/bluetooth_tile_dialog.xml
@@ -51,13 +51,14 @@
android:textAppearance="@style/TextAppearance.Dialog.Body.Message"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toTopOf="@+id/scroll_view"
app:layout_constraintTop_toBottomOf="@id/bluetooth_tile_dialog_title" />
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginTop="21dp"
+ android:fillViewport="true"
app:layout_constrainedHeight="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -84,13 +85,13 @@
android:textSize="16sp"
app:layout_constraintEnd_toStartOf="@+id/bluetooth_toggle"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toTopOf="@+id/device_list"
app:layout_constraintTop_toTopOf="parent" />
<Switch
android:id="@+id/bluetooth_toggle"
android:layout_width="wrap_content"
android:layout_height="48dp"
+ android:paddingTop="10dp"
android:gravity="start|center_vertical"
android:paddingEnd="40dp"
android:contentDescription="@string/turn_on_bluetooth"
@@ -100,14 +101,13 @@
android:track="@drawable/settingslib_track_selector"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/bluetooth_toggle_title"
- app:layout_constraintBottom_toTopOf="@+id/device_list"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/device_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="10dp"
+ android:layout_marginTop="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/bluetooth_toggle"
@@ -146,6 +146,7 @@
android:background="@drawable/bluetooth_tile_dialog_bg_off"
android:layout_width="0dp"
android:layout_height="64dp"
+ android:layout_marginBottom="9dp"
android:contentDescription="@string/accessibility_bluetooth_device_settings_pair_new_device"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@@ -177,7 +178,6 @@
android:maxLines="1"
android:text="@string/inline_done_button"
app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toBottomOf="@id/pair_new_device_button"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index ca0fb85beb6e..87c31c8b8aae 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -26,6 +26,12 @@
android:layout_height="match_parent"
android:fitsSystemWindows="true">
+ <!-- Placeholder for the communal UI that will be replaced if the feature is enabled. -->
+ <ViewStub
+ android:id="@+id/communal_ui_stub"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
<com.android.systemui.scrim.ScrimView
android:id="@+id/scrim_behind"
android:layout_width="match_parent"
@@ -64,12 +70,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
- <!-- Placeholder for the communal UI that will be replaced if the feature is enabled. -->
- <ViewStub
- android:id="@+id/communal_ui_stub"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
<include layout="@layout/brightness_mirror_container" />
<com.android.systemui.scrim.ScrimView
diff --git a/packages/SystemUI/res/layout/widget_picker.xml b/packages/SystemUI/res/layout/widget_picker.xml
index 827bd5d2e0b1..21dc224a6f14 100644
--- a/packages/SystemUI/res/layout/widget_picker.xml
+++ b/packages/SystemUI/res/layout/widget_picker.xml
@@ -14,13 +14,17 @@
~ limitations under the License.
-->
-<LinearLayout
+<HorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/widgets_container"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:padding="64dp"
- android:gravity="center_vertical"
- android:orientation="horizontal">
+ android:layout_height="match_parent">
-</LinearLayout>
+ <LinearLayout
+ android:id="@+id/widgets_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="horizontal">
+ </LinearLayout>
+
+</HorizontalScrollView>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 33a0a06e940c..deed6c8c7f25 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -543,12 +543,16 @@
<!-- ID for the camera of outer display that needs extra protection -->
<string translatable="false" name="config_protectedCameraId"></string>
+ <!-- Physical ID for the camera of outer display that needs extra protection -->
+ <string translatable="false" name="config_protectedPhysicalCameraId"></string>
<!-- Similar to config_frontBuiltInDisplayCutoutProtection but for inner display. -->
<string translatable="false" name="config_innerBuiltInDisplayCutoutProtection"></string>
<!-- ID for the camera of inner display that needs extra protection -->
<string translatable="false" name="config_protectedInnerCameraId"></string>
+ <!-- Physical ID for the camera of inner display that needs extra protection -->
+ <string translatable="false" name="config_protectedInnerPhysicalCameraId"></string>
<!-- Comma-separated list of packages to exclude from camera protection e.g.
"com.android.systemui,com.android.xyz" -->
diff --git a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
index d33d279023da..5f5cca86cce6 100644
--- a/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/CameraAvailabilityListener.kt
@@ -38,26 +38,75 @@ class CameraAvailabilityListener(
excludedPackages: String,
private val executor: Executor
) {
+ private var activeProtectionInfo: CameraProtectionInfo? = null
+ private var openCamera: OpenCameraInfo? = null
+ private val unavailablePhysicalCameras = mutableSetOf<String>()
private val excludedPackageIds: Set<String>
private val listeners = mutableListOf<CameraTransitionCallback>()
private val availabilityCallback: CameraManager.AvailabilityCallback =
- object : CameraManager.AvailabilityCallback() {
- override fun onCameraClosed(cameraId: String) {
- cameraProtectionInfoList.forEach {
- if (cameraId == it.cameraId) {
- notifyCameraInactive()
- }
+ object : CameraManager.AvailabilityCallback() {
+ override fun onCameraClosed(logicalCameraId: String) {
+ openCamera = null
+ if (activeProtectionInfo?.logicalCameraId == logicalCameraId) {
+ notifyCameraInactive()
+ }
+ activeProtectionInfo = null
+ }
+
+ override fun onCameraOpened(logicalCameraId: String, packageId: String) {
+ openCamera = OpenCameraInfo(logicalCameraId, packageId)
+ if (isExcluded(packageId)) {
+ return
+ }
+ val protectionInfo =
+ cameraProtectionInfoList.firstOrNull {
+ logicalCameraId == it.logicalCameraId &&
+ it.physicalCameraId !in unavailablePhysicalCameras
}
+ if (protectionInfo != null) {
+ activeProtectionInfo = protectionInfo
+ notifyCameraActive(protectionInfo)
}
+ }
- override fun onCameraOpened(cameraId: String, packageId: String) {
- cameraProtectionInfoList.forEach {
- if (cameraId == it.cameraId && !isExcluded(packageId)) {
- notifyCameraActive(it)
- }
+ override fun onPhysicalCameraAvailable(
+ logicalCameraId: String,
+ physicalCameraId: String
+ ) {
+ unavailablePhysicalCameras -= physicalCameraId
+ val openCamera = this@CameraAvailabilityListener.openCamera ?: return
+ if (openCamera.logicalCameraId != logicalCameraId) {
+ return
+ }
+ if (isExcluded(openCamera.packageId)) {
+ return
+ }
+ val newActiveInfo =
+ cameraProtectionInfoList.find {
+ it.logicalCameraId == logicalCameraId &&
+ it.physicalCameraId == physicalCameraId
}
+ if (newActiveInfo != null) {
+ activeProtectionInfo = newActiveInfo
+ notifyCameraActive(newActiveInfo)
}
- }
+ }
+
+ override fun onPhysicalCameraUnavailable(
+ logicalCameraId: String,
+ physicalCameraId: String
+ ) {
+ unavailablePhysicalCameras += physicalCameraId
+ val activeInfo = activeProtectionInfo ?: return
+ if (
+ activeInfo.logicalCameraId == logicalCameraId &&
+ activeInfo.physicalCameraId == physicalCameraId
+ ) {
+ activeProtectionInfo = null
+ notifyCameraInactive()
+ }
+ }
+ }
init {
excludedPackageIds = excludedPackages.split(",").toSet()
@@ -106,24 +155,21 @@ class CameraAvailabilityListener(
listeners.forEach { it.onHideCameraProtection() }
}
- /**
- * Callbacks to tell a listener that a relevant camera turned on and off.
- */
+ /** Callbacks to tell a listener that a relevant camera turned on and off. */
interface CameraTransitionCallback {
fun onApplyCameraProtection(protectionPath: Path, bounds: Rect)
+
fun onHideCameraProtection()
}
companion object Factory {
fun build(context: Context, executor: Executor): CameraAvailabilityListener {
- val manager = context
- .getSystemService(Context.CAMERA_SERVICE) as CameraManager
+ val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
val res = context.resources
val cameraProtectionInfoList = loadCameraProtectionInfoList(res)
val excluded = res.getString(R.string.config_cameraProtectionExcludedPackages)
- return CameraAvailabilityListener(
- manager, cameraProtectionInfoList, excluded, executor)
+ return CameraAvailabilityListener(manager, cameraProtectionInfoList, excluded, executor)
}
private fun pathFromString(pathString: String): Path {
@@ -140,19 +186,23 @@ class CameraAvailabilityListener(
private fun loadCameraProtectionInfoList(res: Resources): List<CameraProtectionInfo> {
val list = mutableListOf<CameraProtectionInfo>()
- val front = loadCameraProtectionInfo(
+ val front =
+ loadCameraProtectionInfo(
res,
R.string.config_protectedCameraId,
+ R.string.config_protectedPhysicalCameraId,
R.string.config_frontBuiltInDisplayCutoutProtection
- )
+ )
if (front != null) {
list.add(front)
}
- val inner = loadCameraProtectionInfo(
+ val inner =
+ loadCameraProtectionInfo(
res,
R.string.config_protectedInnerCameraId,
+ R.string.config_protectedInnerPhysicalCameraId,
R.string.config_innerBuiltInDisplayCutoutProtection
- )
+ )
if (inner != null) {
list.add(inner)
}
@@ -160,30 +210,44 @@ class CameraAvailabilityListener(
}
private fun loadCameraProtectionInfo(
- res: Resources,
- cameraIdRes: Int,
- pathRes: Int
+ res: Resources,
+ cameraIdRes: Int,
+ physicalCameraIdRes: Int,
+ pathRes: Int
): CameraProtectionInfo? {
- val cameraId = res.getString(cameraIdRes)
- if (cameraId == null || cameraId.isEmpty()) {
+ val logicalCameraId = res.getString(cameraIdRes)
+ if (logicalCameraId.isNullOrEmpty()) {
return null
}
+ val physicalCameraId = res.getString(physicalCameraIdRes)
val protectionPath = pathFromString(res.getString(pathRes))
val computed = RectF()
protectionPath.computeBounds(computed)
- val protectionBounds = Rect(
+ val protectionBounds =
+ Rect(
computed.left.roundToInt(),
computed.top.roundToInt(),
computed.right.roundToInt(),
computed.bottom.roundToInt()
+ )
+ return CameraProtectionInfo(
+ logicalCameraId,
+ physicalCameraId,
+ protectionPath,
+ protectionBounds
)
- return CameraProtectionInfo(cameraId, protectionPath, protectionBounds)
}
}
- data class CameraProtectionInfo (
- val cameraId: String,
- val cutoutProtectionPath: Path,
- val cutoutBounds: Rect
+ data class CameraProtectionInfo(
+ val logicalCameraId: String,
+ val physicalCameraId: String?,
+ val cutoutProtectionPath: Path,
+ val cutoutBounds: Rect,
+ )
+
+ private data class OpenCameraInfo(
+ val logicalCameraId: String,
+ val packageId: String,
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 70750a1dafb5..0be206d1f75a 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -73,7 +73,8 @@ public final class Prefs {
Key.ACCESSIBILITY_FLOATING_MENU_POSITION,
Key.HAS_CLICKED_NUDGE_TO_SETUP_DREAM,
Key.HAS_DISMISSED_NUDGE_TO_SETUP_DREAM,
- Key.HAS_ACCESSIBILITY_FLOATING_MENU_TUCKED
+ Key.HAS_ACCESSIBILITY_FLOATING_MENU_TUCKED,
+ Key.BLUETOOTH_TILE_DIALOG_CONTENT_HEIGHT,
})
// TODO: annotate these with their types so {@link PrefsCommandLine} can know how to set them
public @interface Key {
@@ -119,6 +120,7 @@ public final class Prefs {
String HAS_CLICKED_NUDGE_TO_SETUP_DREAM = "HasClickedNudgeToSetupDream";
String HAS_DISMISSED_NUDGE_TO_SETUP_DREAM = "HasDismissedNudgeToSetupDream";
String HAS_ACCESSIBILITY_FLOATING_MENU_TUCKED = "HasAccessibilityFloatingMenuTucked";
+ String BLUETOOTH_TILE_DIALOG_CONTENT_HEIGHT = "BluetoothTileDialogContentHeight";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 6faee8cd1c4f..008de4387c4a 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -179,6 +179,7 @@ public class ScreenDecorations implements CoreStartable, Dumpable {
@VisibleForTesting
protected DisplayInfo mDisplayInfo = new DisplayInfo();
private DisplayCutout mDisplayCutout;
+ private boolean mPendingManualConfigUpdate;
@VisibleForTesting
protected void showCameraProtection(@NonNull Path protectionPath, @NonNull Rect bounds) {
@@ -571,6 +572,11 @@ public class ScreenDecorations implements CoreStartable, Dumpable {
setupDecorations();
return;
}
+
+ if (mPendingManualConfigUpdate) {
+ mPendingManualConfigUpdate = false;
+ onConfigurationChanged(mContext.getResources().getConfiguration());
+ }
}
}
};
@@ -1064,6 +1070,15 @@ public class ScreenDecorations implements CoreStartable, Dumpable {
mExecutor.execute(() -> {
Trace.beginSection("ScreenDecorations#onConfigurationChanged");
+ mContext.getDisplay().getDisplayInfo(mDisplayInfo);
+ if (displaySizeChanged(mDisplaySize, mDisplayInfo)) {
+ // We expect the display change event to happen first, but in this case, we received
+ // onConfigurationChanged first.
+ // Return so that we handle the display change event first, and then manually
+ // trigger the config update.
+ mPendingManualConfigUpdate = true;
+ return;
+ }
int oldRotation = mRotation;
mPendingConfigChange = false;
updateConfiguration();
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
index 24aa11e10f30..8c2d221e3f97 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/AccessibilityModule.kt
@@ -18,6 +18,8 @@ package com.android.systemui.accessibility
import com.android.systemui.accessibility.data.repository.ColorCorrectionRepository
import com.android.systemui.accessibility.data.repository.ColorCorrectionRepositoryImpl
+import com.android.systemui.accessibility.data.repository.ColorInversionRepository
+import com.android.systemui.accessibility.data.repository.ColorInversionRepositoryImpl
import com.android.systemui.accessibility.qs.QSAccessibilityModule
import dagger.Binds
import dagger.Module
@@ -25,7 +27,8 @@ import dagger.Module
@Module(includes = [QSAccessibilityModule::class])
interface AccessibilityModule {
@Binds
- abstract fun colorCorrectionRepository(
- impl: ColorCorrectionRepositoryImpl
- ): ColorCorrectionRepository
+ fun colorCorrectionRepository(impl: ColorCorrectionRepositoryImpl): ColorCorrectionRepository
+
+ @Binds
+ fun colorInversionRepository(impl: ColorInversionRepositoryImpl): ColorInversionRepository
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorInversionRepository.kt b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorInversionRepository.kt
new file mode 100644
index 000000000000..bbf10c509e50
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/data/repository/ColorInversionRepository.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.data.repository
+
+import android.os.UserHandle
+import android.provider.Settings.Secure
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.settings.SecureSettings
+import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
+import javax.inject.Inject
+import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
+
+/** Provides data related to color inversion. */
+interface ColorInversionRepository {
+ /** Observable for whether color inversion is enabled */
+ fun isEnabled(userHandle: UserHandle): Flow<Boolean>
+
+ /** Sets color inversion enabled state. */
+ suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean
+}
+
+@SysUISingleton
+class ColorInversionRepositoryImpl
+@Inject
+constructor(
+ @Background private val bgCoroutineContext: CoroutineContext,
+ private val secureSettings: SecureSettings,
+) : ColorInversionRepository {
+
+ override fun isEnabled(userHandle: UserHandle): Flow<Boolean> =
+ secureSettings
+ .observerFlow(userHandle.identifier, SETTING_NAME)
+ .onStart { emit(Unit) }
+ .map { secureSettings.getIntForUser(SETTING_NAME, userHandle.identifier) == ENABLED }
+ .distinctUntilChanged()
+ .flowOn(bgCoroutineContext)
+
+ override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean =
+ withContext(bgCoroutineContext) {
+ secureSettings.putIntForUser(
+ SETTING_NAME,
+ if (isEnabled) ENABLED else DISABLED,
+ userHandle.identifier
+ )
+ }
+
+ companion object {
+ private const val SETTING_NAME = Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED
+ private const val DISABLED = 0
+ private const val ENABLED = 1
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
index df7fdb8e6058..135ab35a4681 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/qs/QSAccessibilityModule.kt
@@ -31,6 +31,10 @@ import com.android.systemui.qs.tiles.impl.colorcorrection.domain.ColorCorrection
import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionTileDataInteractor
import com.android.systemui.qs.tiles.impl.colorcorrection.domain.interactor.ColorCorrectionUserActionInteractor
import com.android.systemui.qs.tiles.impl.colorcorrection.domain.model.ColorCorrectionTileModel
+import com.android.systemui.qs.tiles.impl.inversion.domain.ColorInversionTileMapper
+import com.android.systemui.qs.tiles.impl.inversion.domain.interactor.ColorInversionTileDataInteractor
+import com.android.systemui.qs.tiles.impl.inversion.domain.interactor.ColorInversionUserActionInteractor
+import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel
import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileUIConfig
import com.android.systemui.qs.tiles.viewmodel.QSTileViewModel
@@ -87,8 +91,8 @@ interface QSAccessibilityModule {
fun bindFontScalingTile(fontScalingTile: FontScalingTile): QSTileImpl<*>
companion object {
-
const val COLOR_CORRECTION_TILE_SPEC = "color_correction"
+ const val COLOR_INVERSION_TILE_SPEC = "inversion"
@Provides
@IntoMap
@@ -120,5 +124,36 @@ interface QSAccessibilityModule {
stateInteractor,
mapper,
)
+
+ @Provides
+ @IntoMap
+ @StringKey(COLOR_INVERSION_TILE_SPEC)
+ fun provideColorInversionTileConfig(uiEventLogger: QsEventLogger): QSTileConfig =
+ QSTileConfig(
+ tileSpec = TileSpec.create(COLOR_INVERSION_TILE_SPEC),
+ uiConfig =
+ QSTileUIConfig.Resource(
+ iconRes = R.drawable.qs_invert_colors_icon_off,
+ labelRes = R.string.quick_settings_inversion_label,
+ ),
+ instanceId = uiEventLogger.getNewInstanceId(),
+ )
+
+ /** Inject ColorInversionTile into tileViewModelMap in QSModule */
+ @Provides
+ @IntoMap
+ @StringKey(COLOR_INVERSION_TILE_SPEC)
+ fun provideColorInversionTileViewModel(
+ factory: QSTileViewModelFactory.Static<ColorInversionTileModel>,
+ mapper: ColorInversionTileMapper,
+ stateInteractor: ColorInversionTileDataInteractor,
+ userActionInteractor: ColorInversionUserActionInteractor
+ ): QSTileViewModel =
+ factory.create(
+ TileSpec.create(COLOR_INVERSION_TILE_SPEC),
+ userActionInteractor,
+ stateInteractor,
+ mapper,
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt
index c5610c877f57..75f9d809cc69 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/smartspace/CommunalSmartspaceController.kt
@@ -30,9 +30,9 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin.SmartspaceView
import com.android.systemui.plugins.BcSmartspaceDataPlugin.UI_SURFACE_GLANCEABLE_HUB
import com.android.systemui.smartspace.SmartspacePrecondition
import com.android.systemui.smartspace.SmartspaceTargetFilter
-import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_PRECONDITION
-import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_TARGET_FILTER
import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.LOCKSCREEN_SMARTSPACE_PRECONDITION
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.LOCKSCREEN_SMARTSPACE_TARGET_FILTER
import com.android.systemui.util.concurrency.Execution
import java.util.Optional
import java.util.concurrent.Executor
@@ -48,8 +48,8 @@ constructor(
private val smartspaceManager: SmartspaceManager?,
private val execution: Execution,
@Main private val uiExecutor: Executor,
- @Named(DREAM_SMARTSPACE_PRECONDITION) private val precondition: SmartspacePrecondition,
- @Named(DREAM_SMARTSPACE_TARGET_FILTER)
+ @Named(LOCKSCREEN_SMARTSPACE_PRECONDITION) private val precondition: SmartspacePrecondition,
+ @Named(LOCKSCREEN_SMARTSPACE_TARGET_FILTER)
private val optionalTargetFilter: Optional<SmartspaceTargetFilter>,
@Named(GLANCEABLE_HUB_SMARTSPACE_DATA_PLUGIN) optionalPlugin: Optional<BcSmartspaceDataPlugin>,
) {
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
index 573a748b4290..887b18cfe4c9 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/EditWidgetsActivity.kt
@@ -19,7 +19,9 @@ package com.android.systemui.communal.widgets
import android.appwidget.AppWidgetProviderInfo
import android.content.Intent
import android.os.Bundle
+import android.os.RemoteException
import android.util.Log
+import android.view.IWindowManager
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult
@@ -34,6 +36,7 @@ class EditWidgetsActivity
constructor(
private val communalViewModel: CommunalEditModeViewModel,
private val communalInteractor: CommunalInteractor,
+ private var windowManagerService: IWindowManager? = null,
) : ComponentActivity() {
companion object {
/**
@@ -77,8 +80,12 @@ constructor(
)
},
onEditDone = {
- // TODO(b/315154364): in a separate change, lock the device and transition to GH
- finish()
+ try {
+ checkNotNull(windowManagerService).lockNow(/* options */ null)
+ finish()
+ } catch (e: RemoteException) {
+ Log.e(TAG, "Couldn't lock the device as WindowManager is dead.")
+ }
}
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetPickerActivity.kt b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetPickerActivity.kt
index a2765486bf2d..a26afc86aa2e 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetPickerActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/widgets/WidgetPickerActivity.kt
@@ -19,13 +19,15 @@ package com.android.systemui.communal.widgets
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProviderInfo
import android.content.Intent
+import android.graphics.Color
import android.os.Bundle
-import android.util.DisplayMetrics
import android.util.Log
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.activity.ComponentActivity
+import androidx.core.view.setMargins
+import androidx.core.view.setPadding
import com.android.systemui.res.R
import javax.inject.Inject
@@ -43,7 +45,6 @@ constructor(
super.onCreate(savedInstanceState)
setContentView(R.layout.widget_picker)
-
loadWidgets()
}
@@ -54,24 +55,38 @@ constructor(
appWidgetManager
.getInstalledProviders(AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD)
?.stream()
- ?.limit(5)
?.forEach { widgetInfo ->
val activity = this@WidgetPickerActivity
- val widgetPreview =
- widgetInfo.loadPreviewImage(activity, DisplayMetrics.DENSITY_HIGH)
- val widgetView = ImageView(activity)
- val lp = LinearLayout.LayoutParams(WIDGET_PREVIEW_SIZE, WIDGET_PREVIEW_SIZE)
- widgetView.setLayoutParams(lp)
- widgetView.setImageDrawable(widgetPreview)
- widgetView.setOnClickListener({
- setResult(
- RESULT_OK,
- Intent().putExtra(EditWidgetsActivity.ADD_WIDGET_INFO, widgetInfo)
- )
- finish()
- })
-
- addView(widgetView)
+ (widgetInfo.loadPreviewImage(activity, 0)
+ ?: widgetInfo.loadIcon(activity, 0))
+ ?.let {
+ addView(
+ ImageView(activity).also { v ->
+ v.setImageDrawable(it)
+ v.setBackgroundColor(WIDGET_PREVIEW_BACKGROUND_COLOR)
+ v.setPadding(WIDGET_PREVIEW_PADDING)
+ v.layoutParams =
+ LinearLayout.LayoutParams(
+ WIDGET_PREVIEW_SIZE,
+ WIDGET_PREVIEW_SIZE
+ )
+ .also { lp ->
+ lp.setMargins(WIDGET_PREVIEW_MARGINS)
+ }
+ v.setOnClickListener {
+ setResult(
+ RESULT_OK,
+ Intent()
+ .putExtra(
+ EditWidgetsActivity.ADD_WIDGET_INFO,
+ widgetInfo
+ )
+ )
+ finish()
+ }
+ }
+ )
+ }
}
} catch (e: RuntimeException) {
Log.e(TAG, "Exception fetching widget providers", e)
@@ -80,7 +95,10 @@ constructor(
}
companion object {
- private const val WIDGET_PREVIEW_SIZE = 400
+ private const val WIDGET_PREVIEW_SIZE = 600
+ private const val WIDGET_PREVIEW_MARGINS = 32
+ private const val WIDGET_PREVIEW_PADDING = 32
+ private val WIDGET_PREVIEW_BACKGROUND_COLOR = Color.rgb(216, 225, 220)
private const val TAG = "WidgetPickerActivity"
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
index ca4ef0d0bd8f..4a8c040e33c1 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/dreams/smartspace/DreamSmartspaceController.kt
@@ -34,9 +34,9 @@ import com.android.systemui.plugins.BcSmartspaceDataPlugin.UI_SURFACE_DREAM
import com.android.systemui.smartspace.SmartspacePrecondition
import com.android.systemui.smartspace.SmartspaceTargetFilter
import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_DATA_PLUGIN
-import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_PRECONDITION
-import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_SMARTSPACE_TARGET_FILTER
import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.DREAM_WEATHER_SMARTSPACE_DATA_PLUGIN
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.LOCKSCREEN_SMARTSPACE_PRECONDITION
+import com.android.systemui.smartspace.dagger.SmartspaceModule.Companion.LOCKSCREEN_SMARTSPACE_TARGET_FILTER
import com.android.systemui.smartspace.dagger.SmartspaceViewComponent
import com.android.systemui.util.concurrency.Execution
import java.util.Optional
@@ -54,8 +54,8 @@ class DreamSmartspaceController @Inject constructor(
private val execution: Execution,
@Main private val uiExecutor: Executor,
private val smartspaceViewComponentFactory: SmartspaceViewComponent.Factory,
- @Named(DREAM_SMARTSPACE_PRECONDITION) private val precondition: SmartspacePrecondition,
- @Named(DREAM_SMARTSPACE_TARGET_FILTER)
+ @Named(LOCKSCREEN_SMARTSPACE_PRECONDITION) private val precondition: SmartspacePrecondition,
+ @Named(LOCKSCREEN_SMARTSPACE_TARGET_FILTER)
private val optionalTargetFilter: Optional<SmartspaceTargetFilter>,
@Named(DREAM_SMARTSPACE_DATA_PLUGIN) optionalPlugin: Optional<BcSmartspaceDataPlugin>,
@Named(DREAM_WEATHER_SMARTSPACE_DATA_PLUGIN)
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b1d4587c20d8..b43f54de4b2a 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -564,6 +564,13 @@ object Flags {
val ENABLE_UNFOLD_STATUS_BAR_ANIMATIONS =
unreleasedFlag("enable_unfold_status_bar_animations")
+ // TODO(b/316157842): Tracking Bug
+ // Adds extra delay to notifications measure
+ @Keep
+ @JvmField
+ val ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE =
+ unreleasedFlag("enable_notifications_simulate_slow_measure")
+
// TODO(b259590361): Tracking bug
val EXPERIMENTAL_FLAG = unreleasedFlag("exp_flag_release")
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 45433e62f214..3de9e68909cf 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -1054,6 +1054,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
return;
}
Trace.instantForTrack(Trace.TRACE_TAG_APP, "bugreport", "BugReportAction#onPress");
+ Log.d(TAG, "BugReportAction#onPress");
// Add a little delay before executing, to give the
// dialog a chance to go away before it takes a
// screenshot.
@@ -1069,6 +1070,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
Log.w(TAG, "Bugreport handler could not be launched");
Trace.instantForTrack(Trace.TRACE_TAG_APP, "bugreport",
"BugReportAction#requestingInteractiveBugReport");
+ Log.d(TAG, "BugReportAction#requestingInteractiveBugReport");
mIActivityManager.requestInteractiveBugReport();
}
} catch (RemoteException e) {
@@ -1090,6 +1092,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene
mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS);
Trace.instantForTrack(Trace.TRACE_TAG_APP, "bugreport",
"BugReportAction#requestingFullBugReport");
+ Log.d(TAG, "BugReportAction#requestingFullBugReport");
mIActivityManager.requestFullBugReport();
} catch (RemoteException e) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
index cae6147b03ee..f5bcab96a5a4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/KeyguardState.kt
@@ -80,6 +80,11 @@ enum class KeyguardState {
return state != GONE
}
+ /** Whether either of the bouncers are visible when we're FINISHED in the given state. */
+ fun isBouncerState(state: KeyguardState): Boolean {
+ return state == PRIMARY_BOUNCER || state == ALTERNATE_BOUNCER
+ }
+
/**
* Whether the device is awake ([PowerInteractor.isAwake]) when we're FINISHED in the given
* keyguard state.
@@ -107,4 +112,4 @@ enum class KeyguardState {
return !deviceIsAwakeInState(state)
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
index 789a1e401ae6..e08eb37b79ba 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -66,7 +66,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
*/
public class TileLifecycleManager extends BroadcastReceiver implements
IQSTileService, ServiceConnection, IBinder.DeathRecipient {
- public static final boolean DEBUG = false;
+
+ private final boolean mDebug = Log.isLoggable(TAG, Log.DEBUG);
private static final String TAG = "TileLifecycleManager";
@@ -101,7 +102,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
private Set<Integer> mQueuedMessages = new ArraySet<>();
@Nullable
- private QSTileServiceWrapper mWrapper;
+ private volatile QSTileServiceWrapper mWrapper;
private boolean mListening;
private IBinder mClickBinder;
@@ -132,7 +133,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
mPackageManagerAdapter = packageManagerAdapter;
mBroadcastDispatcher = broadcastDispatcher;
mActivityManager = activityManager;
- if (DEBUG) Log.d(TAG, "Creating " + mIntent + " " + mUser);
+ if (mDebug) Log.d(TAG, "Creating " + mIntent + " " + mUser);
}
/** Injectable factory for TileLifecycleManager. */
@@ -215,10 +216,11 @@ public class TileLifecycleManager extends BroadcastReceiver implements
if (!checkComponentState()) {
return;
}
- if (DEBUG) Log.d(TAG, "Binding service " + mIntent + " " + mUser);
+ if (mDebug) Log.d(TAG, "Binding service " + mIntent + " " + mUser);
mBindTryCount++;
try {
- mIsBound.set(bindServices());
+ // Only try a new binding if we are not currently bound.
+ mIsBound.compareAndSet(false, bindServices());
if (!mIsBound.get()) {
mContext.unbindService(this);
}
@@ -227,19 +229,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
mIsBound.set(false);
}
} else {
- if (DEBUG) Log.d(TAG, "Unbinding service " + mIntent + " " + mUser);
- // Give it another chance next time it needs to be bound, out of kindness.
- mBindTryCount = 0;
- freeWrapper();
- if (mIsBound.get()) {
- try {
- mContext.unbindService(this);
- } catch (Exception e) {
- Log.e(TAG, "Failed to unbind service "
- + mIntent.getComponent().flattenToShortString(), e);
- }
- mIsBound.set(false);
- }
+ unbindService();
}
}
@@ -264,9 +254,26 @@ public class TileLifecycleManager extends BroadcastReceiver implements
mUser);
}
+ @WorkerThread
+ private void unbindService() {
+ if (mDebug) Log.d(TAG, "Unbinding service " + mIntent + " " + mUser);
+ // Give it another chance next time it needs to be bound, out of kindness.
+ mBindTryCount = 0;
+ freeWrapper();
+ if (mIsBound.get()) {
+ try {
+ mContext.unbindService(this);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to unbind service "
+ + mIntent.getComponent().flattenToShortString(), e);
+ }
+ mIsBound.set(false);
+ }
+ }
+
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) Log.d(TAG, "onServiceConnected " + name);
+ if (mDebug) Log.d(TAG, "onServiceConnected " + name);
// Got a connection, set the binding count to 0.
mBindTryCount = 0;
final QSTileServiceWrapper wrapper = new QSTileServiceWrapper(Stub.asInterface(service));
@@ -284,11 +291,17 @@ public class TileLifecycleManager extends BroadcastReceiver implements
}
@Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Log.d(TAG, "onServiceDisconnected " + name);
+ public void onBindingDied(ComponentName name) {
+ if (mDebug) Log.d(TAG, "onBindingDied " + name);
handleDeath();
}
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (mDebug) Log.d(TAG, "onServiceDisconnected " + name);
+ freeWrapper();
+ }
+
private void handlePendingMessages() {
// This ordering is laid out manually to make sure we preserve the TileService
// lifecycle.
@@ -298,35 +311,36 @@ public class TileLifecycleManager extends BroadcastReceiver implements
mQueuedMessages.clear();
}
if (queue.contains(MSG_ON_ADDED)) {
- if (DEBUG) Log.d(TAG, "Handling pending onAdded");
+ if (mDebug) Log.d(TAG, "Handling pending onAdded " + getComponent());
onTileAdded();
}
if (mListening) {
- if (DEBUG) Log.d(TAG, "Handling pending onStartListening");
+ if (mDebug) Log.d(TAG, "Handling pending onStartListening " + getComponent());
onStartListening();
}
if (queue.contains(MSG_ON_CLICK)) {
- if (DEBUG) Log.d(TAG, "Handling pending onClick");
+ if (mDebug) Log.d(TAG, "Handling pending onClick " + getComponent());
if (!mListening) {
- Log.w(TAG, "Managed to get click on non-listening state...");
+ Log.w(TAG, "Managed to get click on non-listening state... " + getComponent());
// Skipping click since lost click privileges.
} else {
onClick(mClickBinder);
}
}
if (queue.contains(MSG_ON_UNLOCK_COMPLETE)) {
- if (DEBUG) Log.d(TAG, "Handling pending onUnlockComplete");
+ if (mDebug) Log.d(TAG, "Handling pending onUnlockComplete " + getComponent());
if (!mListening) {
- Log.w(TAG, "Managed to get unlock on non-listening state...");
+ Log.w(TAG,
+ "Managed to get unlock on non-listening state... " + getComponent());
// Skipping unlock since lost click privileges.
} else {
onUnlockComplete();
}
}
if (queue.contains(MSG_ON_REMOVED)) {
- if (DEBUG) Log.d(TAG, "Handling pending onRemoved");
+ if (mDebug) Log.d(TAG, "Handling pending onRemoved " + getComponent());
if (mListening) {
- Log.w(TAG, "Managed to get remove in listening state...");
+ Log.w(TAG, "Managed to get remove in listening state... " + getComponent());
onStopListening();
}
onTileRemoved();
@@ -340,28 +354,44 @@ public class TileLifecycleManager extends BroadcastReceiver implements
}
public void handleDestroy() {
- if (DEBUG) Log.d(TAG, "handleDestroy");
+ if (mDebug) Log.d(TAG, "handleDestroy");
if (mPackageReceiverRegistered.get() || mUserReceiverRegistered.get()) {
stopPackageListening();
}
mChangeListener = null;
}
+ /**
+ * Handles a dead binder.
+ *
+ * It means that we need to clean up the binding (calling unbindService). After that, if we
+ * are supposed to be bound, we will try to bind after some amount of time.
+ */
private void handleDeath() {
- if (mWrapper == null) return;
- freeWrapper();
- // Clearly not bound anymore
- mIsBound.set(false);
- if (!mBound.get()) return;
- if (DEBUG) Log.d(TAG, "handleDeath");
- if (checkComponentState()) {
- if (isDeathRebindScheduled.compareAndSet(false, true)) {
- mExecutor.executeDelayed(() -> {
- setBindService(true);
- isDeathRebindScheduled.set(false);
- }, getRebindDelay());
+ mExecutor.execute(() -> {
+ if (!mIsBound.get()) {
+ // If we are already not bound, don't do anything else.
+ return;
}
- }
+ // Clearly we shouldn't be bound anymore
+ if (mDebug) Log.d(TAG, "handleDeath " + getComponent());
+ // Binder died, make sure that we unbind. However, we don't want to call setBindService
+ // as we still may want to rebind.
+ unbindService();
+ // If mBound is true (meaning that we should be bound), then reschedule binding for
+ // later.
+ if (mBound.get() && checkComponentState()) {
+ if (isDeathRebindScheduled.compareAndSet(false, true)) {
+ mExecutor.executeDelayed(() -> {
+ // Only rebind if we are supposed to, but remove the scheduling anyway.
+ if (mBound.get()) {
+ setBindService(true);
+ }
+ isDeathRebindScheduled.set(false);
+ }, getRebindDelay());
+ }
+ }
+ });
}
/**
@@ -379,7 +409,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
} else {
delay = mBindRetryDelay;
}
- Log.i(TAG, "Rebinding with a delay=" + delay);
+ if (mDebug) Log.i(TAG, "Rebinding with a delay=" + delay + " - " + getComponent());
return delay;
}
@@ -392,7 +422,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
}
private void startPackageListening() {
- if (DEBUG) Log.d(TAG, "startPackageListening");
+ if (mDebug) Log.d(TAG, "startPackageListening " + getComponent());
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
@@ -402,7 +432,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
this, mUser, filter, null, mHandler, Context.RECEIVER_EXPORTED);
} catch (Exception ex) {
mPackageReceiverRegistered.set(false);
- Log.e(TAG, "Could not register package receiver", ex);
+ Log.e(TAG, "Could not register package receiver " + getComponent(), ex);
}
filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
try {
@@ -410,12 +440,12 @@ public class TileLifecycleManager extends BroadcastReceiver implements
mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler, mUser);
} catch (Exception ex) {
mUserReceiverRegistered.set(false);
- Log.e(TAG, "Could not register unlock receiver", ex);
+ Log.e(TAG, "Could not register unlock receiver " + getComponent(), ex);
}
}
private void stopPackageListening() {
- if (DEBUG) Log.d(TAG, "stopPackageListening");
+ if (mDebug) Log.d(TAG, "stopPackageListening " + getComponent());
if (mUserReceiverRegistered.compareAndSet(true, false)) {
mBroadcastDispatcher.unregisterReceiver(this);
}
@@ -430,7 +460,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onReceive(Context context, Intent intent) {
- if (DEBUG) Log.d(TAG, "onReceive: " + intent);
+ if (mDebug) Log.d(TAG, "onReceive: " + intent);
if (!Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
Uri data = intent.getData();
String pkgName = data.getEncodedSchemeSpecificPart();
@@ -446,7 +476,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
if (mBound.get()) {
// Trying to bind again will check the state of the package before bothering to
// bind.
- if (DEBUG) Log.d(TAG, "Trying to rebind");
+ if (mDebug) Log.d(TAG, "Trying to rebind " + getComponent());
setBindService(true);
}
@@ -458,7 +488,9 @@ public class TileLifecycleManager extends BroadcastReceiver implements
try {
ServiceInfo si = mPackageManagerAdapter.getServiceInfo(mIntent.getComponent(),
0, mUser.getIdentifier());
- if (DEBUG && si == null) Log.d(TAG, "Can't find component " + mIntent.getComponent());
+ if (mDebug && si == null) {
+ Log.d(TAG, "Can't find component " + mIntent.getComponent());
+ }
return si != null;
} catch (RemoteException e) {
// Shouldn't happen.
@@ -472,7 +504,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
mPackageManagerAdapter.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier());
return true;
} catch (PackageManager.NameNotFoundException e) {
- if (DEBUG) {
+ if (mDebug) {
Log.d(TAG, "Package not available: " + packageName, e);
} else {
Log.d(TAG, "Package not available: " + packageName);
@@ -489,7 +521,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onTileAdded() {
- if (DEBUG) Log.d(TAG, "onTileAdded");
+ if (mDebug) Log.d(TAG, "onTileAdded " + getComponent());
if (mWrapper == null || !mWrapper.onTileAdded()) {
queueMessage(MSG_ON_ADDED);
handleDeath();
@@ -498,7 +530,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onTileRemoved() {
- if (DEBUG) Log.d(TAG, "onTileRemoved");
+ if (mDebug) Log.d(TAG, "onTileRemoved " + getComponent());
if (mWrapper == null || !mWrapper.onTileRemoved()) {
queueMessage(MSG_ON_REMOVED);
handleDeath();
@@ -507,7 +539,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onStartListening() {
- if (DEBUG) Log.d(TAG, "onStartListening");
+ if (mDebug) Log.d(TAG, "onStartListening " + getComponent());
mListening = true;
if (mWrapper != null && !mWrapper.onStartListening()) {
handleDeath();
@@ -516,7 +548,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onStopListening() {
- if (DEBUG) Log.d(TAG, "onStopListening");
+ if (mDebug) Log.d(TAG, "onStopListening " + getComponent());
mListening = false;
if (mWrapper != null && !mWrapper.onStopListening()) {
handleDeath();
@@ -525,7 +557,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onClick(IBinder iBinder) {
- if (DEBUG) Log.d(TAG, "onClick " + iBinder + " " + mUser);
+ if (mDebug) Log.d(TAG, "onClick " + iBinder + " " + getComponent() + " " + mUser);
if (mWrapper == null || !mWrapper.onClick(iBinder)) {
mClickBinder = iBinder;
queueMessage(MSG_ON_CLICK);
@@ -535,7 +567,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void onUnlockComplete() {
- if (DEBUG) Log.d(TAG, "onUnlockComplete");
+ if (mDebug) Log.d(TAG, "onUnlockComplete " + getComponent());
if (mWrapper == null || !mWrapper.onUnlockComplete()) {
queueMessage(MSG_ON_UNLOCK_COMPLETE);
handleDeath();
@@ -550,7 +582,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements
@Override
public void binderDied() {
- if (DEBUG) Log.d(TAG, "binderDeath");
+ if (mDebug) Log.d(TAG, "binderDeath " + getComponent());
handleDeath();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
index db3cf0f70f69..1805eb182cb1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialog.kt
@@ -24,6 +24,7 @@ import android.view.View.AccessibilityDelegate
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.accessibility.AccessibilityNodeInfo
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
import android.widget.ImageView
@@ -54,6 +55,7 @@ internal class BluetoothTileDialog
constructor(
private val bluetoothToggleInitialValue: Boolean,
private val subtitleResIdInitialValue: Int,
+ private val cachedContentHeight: Int,
private val bluetoothTileDialogCallback: BluetoothTileDialogCallback,
@Main private val mainDispatcher: CoroutineDispatcher,
private val systemClock: SystemClock,
@@ -72,6 +74,11 @@ constructor(
internal val deviceItemClick
get() = mutableDeviceItemClick.asSharedFlow()
+ private val mutableContentHeight: MutableSharedFlow<Int> =
+ MutableSharedFlow(extraBufferCapacity = 1)
+ internal val contentHeight
+ get() = mutableContentHeight.asSharedFlow()
+
private val deviceItemAdapter: Adapter = Adapter(bluetoothTileDialogCallback)
private var lastUiUpdateMs: Long = -1
@@ -84,6 +91,7 @@ constructor(
private lateinit var seeAllButton: View
private lateinit var pairNewDeviceButton: View
private lateinit var deviceListView: RecyclerView
+ private lateinit var scrollViewContent: View
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -110,12 +118,23 @@ constructor(
pairNewDeviceButton.setOnClickListener {
bluetoothTileDialogCallback.onPairNewDeviceClicked(it)
}
+ requireViewById<View>(R.id.scroll_view).apply {
+ scrollViewContent = this
+ layoutParams.height = cachedContentHeight
+ }
}
override fun start() {
lastUiUpdateMs = systemClock.elapsedRealtime()
}
+ override fun dismiss() {
+ if (::scrollViewContent.isInitialized) {
+ mutableContentHeight.tryEmit(scrollViewContent.measuredHeight)
+ }
+ super.dismiss()
+ }
+
internal suspend fun onDeviceItemUpdated(
deviceItem: List<DeviceItem>,
showSeeAll: Boolean,
@@ -124,14 +143,16 @@ constructor(
withContext(mainDispatcher) {
val start = systemClock.elapsedRealtime()
val itemRow = deviceItem.size + showSeeAll.toInt() + showPairNewDevice.toInt()
- // Add a slight delay for smoother dialog height change
- if (itemRow != lastItemRow) {
+ // If not the first load, add a slight delay for smoother dialog height change
+ if (itemRow != lastItemRow && lastItemRow != -1) {
delay(MIN_HEIGHT_CHANGE_INTERVAL_MS - (start - lastUiUpdateMs))
}
if (isActive) {
deviceItemAdapter.refreshDeviceItemList(deviceItem) {
seeAllButton.visibility = if (showSeeAll) VISIBLE else GONE
pairNewDeviceButton.visibility = if (showPairNewDevice) VISIBLE else GONE
+ // Update the height after data is updated
+ scrollViewContent.layoutParams.height = WRAP_CONTENT
lastUiUpdateMs = systemClock.elapsedRealtime()
lastItemRow = itemRow
logger.logDeviceUiUpdate(lastUiUpdateMs - start)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
index 5d5e747ba979..6d08f591690f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModel.kt
@@ -18,14 +18,18 @@ package com.android.systemui.qs.tiles.dialog.bluetooth
import android.content.Context
import android.content.Intent
+import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
+import android.view.ViewGroup
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.logging.UiEventLogger
+import com.android.systemui.Prefs
import com.android.systemui.animation.DialogCuj
import com.android.systemui.animation.DialogLaunchAnimator
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialog.Companion.ACTION_BLUETOOTH_DEVICE_DETAILS
@@ -45,6 +49,7 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/** ViewModel for Bluetooth Dialog after clicking on the Bluetooth QS tile. */
@SysUISingleton
@@ -60,6 +65,8 @@ constructor(
private val logger: BluetoothTileDialogLogger,
@Application private val coroutineScope: CoroutineScope,
@Main private val mainDispatcher: CoroutineDispatcher,
+ @Background private val backgroundDispatcher: CoroutineDispatcher,
+ @Main private val sharedPreferences: SharedPreferences,
) : BluetoothTileDialogCallback {
private var job: Job? = null
@@ -145,14 +152,31 @@ constructor(
.onEach { deviceItemInteractor.updateDeviceItemOnClick(it) }
.launchIn(this)
+ dialog.contentHeight
+ .onEach {
+ withContext(backgroundDispatcher) {
+ sharedPreferences.edit().putInt(CONTENT_HEIGHT_PREF_KEY, it).apply()
+ }
+ }
+ .launchIn(this)
+
produce<Unit> { awaitClose { dialog.cancel() } }
}
}
- private fun createBluetoothTileDialog(context: Context): BluetoothTileDialog {
+ private suspend fun createBluetoothTileDialog(context: Context): BluetoothTileDialog {
+ val cachedContentHeight =
+ withContext(backgroundDispatcher) {
+ sharedPreferences.getInt(
+ CONTENT_HEIGHT_PREF_KEY,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ }
+
return BluetoothTileDialog(
bluetoothStateInteractor.isBluetoothEnabled,
getSubtitleResId(bluetoothStateInteractor.isBluetoothEnabled),
+ cachedContentHeight,
this@BluetoothTileDialogViewModel,
mainDispatcher,
systemClock,
@@ -205,6 +229,7 @@ constructor(
companion object {
private const val INTERACTION_JANK_TAG = "bluetooth_tile_dialog"
+ private const val CONTENT_HEIGHT_PREF_KEY = Prefs.Key.BLUETOOTH_TILE_DIALOG_CONTENT_HEIGHT
private fun getSubtitleResId(isBluetoothEnabled: Boolean) =
if (isBluetoothEnabled) R.string.quick_settings_bluetooth_tile_subtitle
else R.string.bt_is_off
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapper.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapper.kt
new file mode 100644
index 000000000000..4af985424a39
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/ColorInversionTileMapper.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.inversion.domain
+
+import android.content.res.Resources
+import android.content.res.Resources.Theme
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataToStateMapper
+import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileConfig
+import com.android.systemui.qs.tiles.viewmodel.QSTileState
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+/** Maps [ColorInversionTileModel] to [QSTileState]. */
+class ColorInversionTileMapper
+@Inject
+constructor(
+ @Main private val resources: Resources,
+ private val theme: Theme,
+) : QSTileDataToStateMapper<ColorInversionTileModel> {
+ override fun map(config: QSTileConfig, data: ColorInversionTileModel): QSTileState =
+ QSTileState.build(resources, theme, config.uiConfig) {
+ val subtitleArray = resources.getStringArray(R.array.tile_states_inversion)
+
+ if (data.isEnabled) {
+ activationState = QSTileState.ActivationState.ACTIVE
+ secondaryLabel = subtitleArray[2]
+ icon = {
+ Icon.Loaded(
+ resources.getDrawable(R.drawable.qs_invert_colors_icon_on, theme),
+ null
+ )
+ }
+ } else {
+ activationState = QSTileState.ActivationState.INACTIVE
+ secondaryLabel = subtitleArray[1]
+ icon = {
+ Icon.Loaded(
+ resources.getDrawable(R.drawable.qs_invert_colors_icon_off, theme),
+ null
+ )
+ }
+ }
+ contentDescription = label
+ supportedActions =
+ setOf(QSTileState.UserAction.CLICK, QSTileState.UserAction.LONG_CLICK)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractor.kt
new file mode 100644
index 000000000000..7f3dd3e17b79
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionTileDataInteractor.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.inversion.domain.interactor
+
+import android.os.UserHandle
+import com.android.systemui.accessibility.data.repository.ColorInversionRepository
+import com.android.systemui.qs.tiles.base.interactor.DataUpdateTrigger
+import com.android.systemui.qs.tiles.base.interactor.QSTileDataInteractor
+import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+/** Observes color inversion state changes providing the [ColorInversionTileModel]. */
+class ColorInversionTileDataInteractor
+@Inject
+constructor(
+ private val colorInversionRepository: ColorInversionRepository,
+) : QSTileDataInteractor<ColorInversionTileModel> {
+
+ override fun tileData(
+ user: UserHandle,
+ triggers: Flow<DataUpdateTrigger>
+ ): Flow<ColorInversionTileModel> {
+ return colorInversionRepository.isEnabled(user).map { ColorInversionTileModel(it) }
+ }
+ override fun availability(user: UserHandle): Flow<Boolean> = flowOf(true)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt
new file mode 100644
index 000000000000..43b58c83f7ef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/interactor/ColorInversionUserActionInteractor.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.inversion.domain.interactor
+
+import android.content.Intent
+import android.provider.Settings
+import com.android.systemui.accessibility.data.repository.ColorInversionRepository
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.interactor.QSTileInput
+import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
+import com.android.systemui.qs.tiles.impl.inversion.domain.model.ColorInversionTileModel
+import com.android.systemui.qs.tiles.viewmodel.QSTileUserAction
+import javax.inject.Inject
+
+/** Handles color inversion tile clicks. */
+class ColorInversionUserActionInteractor
+@Inject
+constructor(
+ private val colorInversionRepository: ColorInversionRepository,
+ private val qsTileIntentUserActionHandler: QSTileIntentUserInputHandler,
+) : QSTileUserActionInteractor<ColorInversionTileModel> {
+
+ override suspend fun handleInput(input: QSTileInput<ColorInversionTileModel>): Unit =
+ with(input) {
+ when (action) {
+ is QSTileUserAction.Click -> {
+ colorInversionRepository.setIsEnabled(
+ !data.isEnabled,
+ user,
+ )
+ }
+ is QSTileUserAction.LongClick -> {
+ qsTileIntentUserActionHandler.handle(
+ action.view,
+ Intent(Settings.ACTION_COLOR_INVERSION_SETTINGS)
+ )
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/model/ColorInversionTileModel.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/model/ColorInversionTileModel.kt
new file mode 100644
index 000000000000..affaa6d533bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/inversion/domain/model/ColorInversionTileModel.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.inversion.domain.model
+
+/**
+ * Color inversion tile model.
+ *
+ * @param isEnabled is true when the color inversion is enabled;
+ */
+@JvmInline value class ColorInversionTileModel(val isEnabled: Boolean)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
new file mode 100644
index 000000000000..ab69acbc6e9d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade
+
+import android.content.Context
+import android.view.GestureDetector
+import android.view.MotionEvent
+import android.view.View
+import com.android.internal.annotations.VisibleForTesting
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
+import com.android.systemui.compose.ComposeFacade.createCommunalContainer
+import com.android.systemui.compose.ComposeFacade.isComposeAvailable
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.res.R
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.util.kotlin.collectFlow
+import javax.inject.Inject
+
+/**
+ * Controller that's responsible for the glanceable hub container view and its touch handling.
+ *
+ * This will be used until the glanceable hub is integrated into Flexiglass.
+ */
+class GlanceableHubContainerController
+@Inject
+constructor(
+ private val communalInteractor: CommunalInteractor,
+ private val communalViewModel: CommunalViewModel,
+ private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+ private val shadeInteractor: ShadeInteractor,
+) {
+ /** The container view for the hub. This will not be initialized until [initView] is called. */
+ private lateinit var communalContainerView: View
+
+ /**
+ * The width of the area in which a right edge swipe can open the hub, in pixels. Read from
+ * resources when [initView] is called.
+ */
+ private var edgeSwipeRegionWidth: Int = 0
+
+ /**
+ * True if we are currently tracking a gesture for opening the hub that started in the edge
+ * swipe region.
+ */
+ private var isTrackingOpenGesture = false
+
+ /**
+ * True if the hub UI is fully open, meaning it should receive touch input.
+ *
+ * Tracks [CommunalInteractor.isCommunalShowing].
+ */
+ private var hubShowing = false
+
+ /**
+ * True if either the primary or alternate bouncer are open, meaning the hub should not receive
+ * any touch input.
+ *
+ * Tracks [KeyguardTransitionInteractor.isFinishedInState] for [KeyguardState.isBouncerState].
+ */
+ private var anyBouncerShowing = false
+
+ /**
+ * True if the shade is fully expanded, meaning the hub should not receive any touch input.
+ *
+ * Tracks [ShadeInteractor.isAnyFullyExpanded].
+ */
+ private var shadeShowing = false
+
+ /** Returns true if the glanceable hub is enabled and the container view can be created. */
+ fun isEnabled(): Boolean {
+ return communalInteractor.isCommunalEnabled && isComposeAvailable()
+ }
+
+ /**
+ * Creates the container view containing the glanceable hub UI.
+ *
+ * @throws RuntimeException if [isEnabled] is false or the view is already initialized
+ */
+ fun initView(
+ context: Context,
+ ): View {
+ return initView(createCommunalContainer(context, communalViewModel))
+ }
+
+ /** Override for testing. */
+ @VisibleForTesting
+ internal fun initView(containerView: View): View {
+ if (!isEnabled()) {
+ throw RuntimeException("Glanceable hub is not enabled")
+ }
+ if (::communalContainerView.isInitialized) {
+ throw RuntimeException("Communal view has already been initialized")
+ }
+
+ communalContainerView = containerView
+
+ edgeSwipeRegionWidth =
+ communalContainerView.resources.getDimensionPixelSize(R.dimen.communal_grid_gutter_size)
+
+ collectFlow(
+ communalContainerView,
+ keyguardTransitionInteractor.isFinishedInStateWhere(KeyguardState::isBouncerState),
+ { anyBouncerShowing = it }
+ )
+ collectFlow(
+ communalContainerView,
+ communalInteractor.isCommunalShowing,
+ { hubShowing = it }
+ )
+ collectFlow(
+ communalContainerView,
+ shadeInteractor.isAnyFullyExpanded,
+ { shadeShowing = it }
+ )
+
+ return communalContainerView
+ }
+
+ /**
+ * Notifies the hub container of a touch event. Returns true if it's determined that the touch
+ * should go to the hub container and no one else.
+ *
+ * Special handling is needed because the hub container sits at the lowest z-order in
+ * [NotificationShadeWindowView] and would not normally receive touches. We also cannot use a
+ * [GestureDetector] as the hub container's SceneTransitionLayout is a Compose view that expects
+ * to be fully in control of its own touch handling.
+ */
+ fun onTouchEvent(ev: MotionEvent): Boolean {
+ if (!::communalContainerView.isInitialized) {
+ return false
+ }
+
+ val isDown = ev.actionMasked == MotionEvent.ACTION_DOWN
+ val isUp = ev.actionMasked == MotionEvent.ACTION_UP
+ val isCancel = ev.actionMasked == MotionEvent.ACTION_CANCEL
+
+ // TODO(b/315207481): also account for opening animations of shade/bouncer and not just
+ // fully showing state
+ val hubOccluded = anyBouncerShowing || shadeShowing
+
+ // If the hub is fully visible, send all touch events to it.
+ val communalVisible = hubShowing && !hubOccluded
+ if (communalVisible) {
+ return communalContainerView.dispatchTouchEvent(ev)
+ }
+
+ if (edgeSwipeRegionWidth == 0) {
+ // If the edge region width has not been read yet or whatever reason, don't bother
+ // intercepting touches to open the hub.
+ return false
+ }
+
+ if (!isTrackingOpenGesture && isDown) {
+ val x = ev.rawX
+ val inOpeningSwipeRegion: Boolean =
+ x >= communalContainerView.width - edgeSwipeRegionWidth
+ if (inOpeningSwipeRegion && !hubOccluded) {
+ isTrackingOpenGesture = true
+ return communalContainerView.dispatchTouchEvent(ev)
+ }
+ } else if (isTrackingOpenGesture) {
+ if (isUp || isCancel) {
+ isTrackingOpenGesture = false
+ }
+ return communalContainerView.dispatchTouchEvent(ev)
+ }
+
+ return false
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 73537edcc94a..07ce57735dc7 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -42,9 +42,6 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor;
import com.android.systemui.bouncer.ui.binder.KeyguardBouncerViewBinder;
import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel;
import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.communal.data.repository.CommunalRepository;
-import com.android.systemui.communal.ui.viewmodel.CommunalViewModel;
-import com.android.systemui.compose.ComposeFacade;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor;
import com.android.systemui.dock.DockManager;
@@ -108,14 +105,14 @@ public class NotificationShadeWindowViewController implements Dumpable {
private final PulsingGestureListener mPulsingGestureListener;
private final LockscreenHostedDreamGestureListener mLockscreenHostedDreamGestureListener;
private final NotificationInsetsController mNotificationInsetsController;
- private final CommunalViewModel mCommunalViewModel;
- private final CommunalRepository mCommunalRepository;
private final boolean mIsTrackpadCommonEnabled;
private final FeatureFlagsClassic mFeatureFlagsClassic;
private final SysUIKeyEventHandler mSysUIKeyEventHandler;
private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
private final AlternateBouncerInteractor mAlternateBouncerInteractor;
private final QuickSettingsController mQuickSettingsController;
+ private final GlanceableHubContainerController
+ mGlanceableHubContainerController;
private GestureDetector mPulsingWakeupGestureHandler;
private GestureDetector mDreamingWakeupGestureHandler;
private View mBrightnessMirror;
@@ -183,8 +180,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
KeyguardMessageAreaController.Factory messageAreaControllerFactory,
KeyguardTransitionInteractor keyguardTransitionInteractor,
PrimaryBouncerToGoneTransitionViewModel primaryBouncerToGoneTransitionViewModel,
- CommunalViewModel communalViewModel,
- CommunalRepository communalRepository,
+ GlanceableHubContainerController glanceableHubContainerController,
NotificationLaunchAnimationInteractor notificationLaunchAnimationInteractor,
FeatureFlagsClassic featureFlagsClassic,
SystemClock clock,
@@ -217,8 +213,7 @@ public class NotificationShadeWindowViewController implements Dumpable {
mPulsingGestureListener = pulsingGestureListener;
mLockscreenHostedDreamGestureListener = lockscreenHostedDreamGestureListener;
mNotificationInsetsController = notificationInsetsController;
- mCommunalViewModel = communalViewModel;
- mCommunalRepository = communalRepository;
+ mGlanceableHubContainerController = glanceableHubContainerController;
mIsTrackpadCommonEnabled = featureFlagsClassic.isEnabled(TRACKPAD_GESTURE_COMMON);
mFeatureFlagsClassic = featureFlagsClassic;
mSysUIKeyEventHandler = sysUIKeyEventHandler;
@@ -347,6 +342,10 @@ public class NotificationShadeWindowViewController implements Dumpable {
mFalsingCollector.onTouchEvent(ev);
mPulsingWakeupGestureHandler.onTouchEvent(ev);
+
+ if (mGlanceableHubContainerController.onTouchEvent(ev)) {
+ return logDownDispatch(ev, "dispatched to glanceable hub container", true);
+ }
if (mDreamingWakeupGestureHandler != null
&& mDreamingWakeupGestureHandler.onTouchEvent(ev)) {
return logDownDispatch(ev, "dream wakeup gesture handled", true);
@@ -587,14 +586,13 @@ public class NotificationShadeWindowViewController implements Dumpable {
}
/**
- * Sets up the communal hub UI if the {@link com.android.systemui.Flags#FLAG_COMMUNAL_HUB} flag
- * is enabled.
+ * Sets up the glanceable hub UI if the {@link com.android.systemui.Flags#FLAG_COMMUNAL_HUB}
+ * flag is enabled.
*
- * The layout lives in {@link R.id.communal_ui_container}.
+ * The layout lives in {@link R.id.communal_ui_stub}.
*/
public void setupCommunalHubLayout() {
- if (!mCommunalRepository.isCommunalEnabled()
- || !ComposeFacade.INSTANCE.isComposeAvailable()) {
+ if (!mGlanceableHubContainerController.isEnabled()) {
return;
}
@@ -602,8 +600,8 @@ public class NotificationShadeWindowViewController implements Dumpable {
View communalPlaceholder = mView.findViewById(R.id.communal_ui_stub);
int index = mView.indexOfChild(communalPlaceholder);
mView.removeView(communalPlaceholder);
- mView.addView(ComposeFacade.INSTANCE.createCommunalContainer(mView.getContext(),
- mCommunalViewModel), index);
+
+ mView.addView(mGlanceableHubContainerController.initView(mView.getContext()), index);
}
private boolean didNotificationPanelInterceptEvent(MotionEvent ev) {
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
index d26fded19cc1..2f58b35ae182 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/dagger/SmartspaceModule.kt
@@ -41,14 +41,14 @@ abstract class SmartspaceModule {
const val DREAM_WEATHER_SMARTSPACE_DATA_PLUGIN = "dream_weather_smartspace_data_plugin"
/**
- * The dream smartspace target filter.
+ * The target filter for smartspace over lockscreen.
*/
- const val DREAM_SMARTSPACE_TARGET_FILTER = "dream_smartspace_target_filter"
+ const val LOCKSCREEN_SMARTSPACE_TARGET_FILTER = "lockscreen_smartspace_target_filter"
/**
- * The precondition for dream smartspace
+ * The precondition for smartspace over lockscreen
*/
- const val DREAM_SMARTSPACE_PRECONDITION = "dream_smartspace_precondition"
+ const val LOCKSCREEN_SMARTSPACE_PRECONDITION = "lockscreen_smartspace_precondition"
/**
* The BcSmartspaceDataPlugin for the standalone date (+alarm+dnd).
@@ -67,7 +67,7 @@ abstract class SmartspaceModule {
}
@BindsOptionalOf
- @Named(DREAM_SMARTSPACE_TARGET_FILTER)
+ @Named(LOCKSCREEN_SMARTSPACE_TARGET_FILTER)
abstract fun optionalDreamSmartspaceTargetFilter(): SmartspaceTargetFilter?
@BindsOptionalOf
@@ -79,7 +79,7 @@ abstract class SmartspaceModule {
abstract fun optionalDreamWeatherSmartspaceDataPlugin(): BcSmartspaceDataPlugin?
@Binds
- @Named(DREAM_SMARTSPACE_PRECONDITION)
+ @Named(LOCKSCREEN_SMARTSPACE_PRECONDITION)
abstract fun bindSmartspacePrecondition(
lockscreenPrecondition: LockscreenPrecondition?
): SmartspacePrecondition?
diff --git a/packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenAndDreamTargetFilter.kt b/packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenTargetFilter.kt
index aa4cf75a7a6e..5fb85e59ad91 100644
--- a/packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenAndDreamTargetFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/smartspace/filters/LockscreenTargetFilter.kt
@@ -31,10 +31,10 @@ import com.android.systemui.util.settings.SecureSettings
import java.util.concurrent.Executor
import javax.inject.Inject
-/**
- * {@link SmartspaceTargetFilter} for smartspace targets that show above the lockscreen and dreams.
- */
-class LockscreenAndDreamTargetFilter @Inject constructor(
+/** {@link SmartspaceTargetFilter} for smartspace targets that show above the lockscreen. */
+class LockscreenTargetFilter
+@Inject
+constructor(
private val secureSettings: SecureSettings,
private val userTracker: UserTracker,
private val execution: Execution,
@@ -60,12 +60,13 @@ class LockscreenAndDreamTargetFilter @Inject constructor(
}
}
- private val settingsObserver = object : ContentObserver(handler) {
- override fun onChange(selfChange: Boolean, uri: Uri?) {
- execution.assertIsMainThread()
- updateUserContentSettings()
+ private val settingsObserver =
+ object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ execution.assertIsMainThread()
+ updateUserContentSettings()
+ }
}
- }
private var managedUserHandle: UserHandle? = null
@@ -79,10 +80,10 @@ class LockscreenAndDreamTargetFilter @Inject constructor(
userTracker.addCallback(userTrackerCallback, uiExecutor)
contentResolver.registerContentObserver(
- secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
- true,
- settingsObserver,
- UserHandle.USER_ALL
+ secureSettings.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
+ true,
+ settingsObserver,
+ UserHandle.USER_ALL
)
updateUserContentSettings()
@@ -110,7 +111,7 @@ class LockscreenAndDreamTargetFilter @Inject constructor(
// Only the primary user can have an associated managed profile, so only show
// content for the managed profile if the primary user is active
userTracker.userHandle.identifier == UserHandle.USER_SYSTEM &&
- (!t.isSensitive || showSensitiveContentForManagedUser)
+ (!t.isSensitive || showSensitiveContentForManagedUser)
}
else -> {
false
@@ -118,12 +119,13 @@ class LockscreenAndDreamTargetFilter @Inject constructor(
}
}
- private val userTrackerCallback = object : UserTracker.Callback {
- override fun onUserChanged(newUser: Int, userContext: Context) {
- execution.assertIsMainThread()
- updateUserContentSettings()
+ private val userTrackerCallback =
+ object : UserTracker.Callback {
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ execution.assertIsMainThread()
+ updateUserContentSettings()
+ }
}
- }
private fun getWorkProfileUser(): UserHandle? {
for (userInfo in userTracker.userProfiles) {
@@ -138,13 +140,13 @@ class LockscreenAndDreamTargetFilter @Inject constructor(
val setting = Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS
showSensitiveContentForCurrentUser =
- secureSettings.getIntForUser(setting, 0, userTracker.userId) == 1
+ secureSettings.getIntForUser(setting, 0, userTracker.userId) == 1
managedUserHandle = getWorkProfileUser()
val managedId = managedUserHandle?.identifier
if (managedId != null) {
showSensitiveContentForManagedUser =
- secureSettings.getIntForUser(setting, 0, managedId) == 1
+ secureSettings.getIntForUser(setting, 0, managedId) == 1
}
listeners.forEach { it.onCriteriaChanged() }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index b6d4dedfe6f7..5872840913f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -38,6 +38,7 @@ import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.FloatProperty;
@@ -272,6 +273,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private final RefactorFlag mInlineReplyAnimation =
RefactorFlag.forView(Flags.NOTIFICATION_INLINE_REPLY_ANIMATION);
+ private static final boolean mSimulateSlowMeasure = Compile.IS_DEBUG && RefactorFlag.forView(
+ Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE).isEnabled();
+ private static final String SLOW_MEASURE_SIMULATE_DELAY_PROPERTY =
+ "persist.notifications.extra_measure_delay_ms";
+ private static final int SLOW_MEASURE_SIMULATE_DELAY_MS = mSimulateSlowMeasure ?
+ SystemProperties.getInt(SLOW_MEASURE_SIMULATE_DELAY_PROPERTY, 150) : 0;
+
// Listener will be called when receiving a long click event.
// Use #setLongPressPosition to optionally assign positional data with the long press.
private LongPressListener mLongPressListener;
@@ -1879,9 +1887,26 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
+ "heightMeasureSpec=" + MeasureSpec.toString(heightMeasureSpec) + ")");
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ if (Compile.IS_DEBUG && mSimulateSlowMeasure) {
+ simulateExtraMeasureDelay();
+ }
Trace.endSection();
}
+ private void simulateExtraMeasureDelay() {
+ // Add extra delay in a notification row instead of NotificationStackScrollLayout
+ // to make sure that when the measure cache is used we won't add this delay
+ try {
+ Trace.beginSection("ExtraDebugMeasureDelay");
+ Thread.sleep(SLOW_MEASURE_SIMULATE_DELAY_MS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } finally {
+ Trace.endSection();
+ }
+ }
+
/**
* Generates and appends "(MessagingStyle)" type tag to passed string for tracing.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index fdf5966419b4..20fef927e8d1 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -317,10 +317,11 @@ public class ImageWallpaper extends WallpaperService {
}
private void loadWallpaperAndDrawFrameInternal() {
- Trace.beginSection("ImageWallpaper.CanvasEngine#loadWallpaper");
+ Trace.beginSection("WPMS.ImageWallpaper.CanvasEngine#loadWallpaper");
boolean loadSuccess = false;
Bitmap bitmap;
try {
+ Trace.beginSection("WPMS.getBitmapAsUser");
bitmap = mWallpaperManager.getBitmapAsUser(
mUserTracker.getUserId(), false, getSourceFlag(), true);
if (bitmap != null
@@ -333,15 +334,22 @@ public class ImageWallpaper extends WallpaperService {
// be loaded, we will go into a cycle. Don't do a build where the
// default wallpaper can't be loaded.
Log.w(TAG, "Unable to load wallpaper!", exception);
+ Trace.beginSection("WPMS.clearWallpaper");
mWallpaperManager.clearWallpaper(getWallpaperFlags(), mUserTracker.getUserId());
+ Trace.endSection();
try {
+ Trace.beginSection("WPMS.getBitmapAsUser_defaultWallpaper");
bitmap = mWallpaperManager.getBitmapAsUser(
mUserTracker.getUserId(), false, getSourceFlag(), true);
} catch (RuntimeException | OutOfMemoryError e) {
Log.w(TAG, "Unable to load default wallpaper!", e);
bitmap = null;
+ } finally {
+ Trace.endSection();
}
+ } finally {
+ Trace.endSection();
}
if (bitmap == null) {
@@ -355,15 +363,23 @@ public class ImageWallpaper extends WallpaperService {
loadSuccess = true;
// recycle the previously loaded bitmap
if (mBitmap != null) {
+ Trace.beginSection("WPMS.mBitmap.recycle");
mBitmap.recycle();
+ Trace.endSection();
}
mBitmap = bitmap;
+ Trace.beginSection("WPMS.wallpaperSupportsWcg");
mWideColorGamut = mWallpaperManager.wallpaperSupportsWcg(getSourceFlag());
+ Trace.endSection();
// +2 usages for the color extraction and the delayed unload.
mBitmapUsages += 2;
+ Trace.beginSection("WPMS.recomputeColorExtractorMiniBitmap");
recomputeColorExtractorMiniBitmap();
+ Trace.endSection();
+ Trace.beginSection("WPMS.drawFrameInternal");
drawFrameInternal();
+ Trace.endSection();
/*
* after loading, the bitmap will be unloaded after all these conditions:
diff --git a/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
index b1421b21b377..e921a59f5860 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/CameraAvailabilityListenerTest.kt
@@ -9,30 +9,34 @@ import android.util.PathParser
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.withArgCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Expect
import java.util.concurrent.Executor
import kotlin.math.roundToInt
-import kotlin.test.assertEquals
-import kotlin.test.assertNotNull
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@SmallTest
class CameraAvailabilityListenerTest : SysuiTestCase() {
companion object {
- const val EXCLUDED_PKG = "test.excluded.package"
- const val CAMERA_ID_FRONT = "0"
- const val CAMERA_ID_INNER = "1"
- const val PROTECTION_PATH_STRING_FRONT = "M 50,50 a 20,20 0 1 0 40,0 a 20,20 0 1 0 -40,0 Z"
- const val PROTECTION_PATH_STRING_INNER = "M 40,40 a 10,10 0 1 0 20,0 a 10,10 0 1 0 -20,0 Z"
- val PATH_RECT_FRONT = rectFromPath(pathFromString(PROTECTION_PATH_STRING_FRONT))
- val PATH_RECT_INNER = rectFromPath(pathFromString(PROTECTION_PATH_STRING_INNER))
+ private const val EXCLUDED_PKG = "test.excluded.package"
+ private const val LOGICAL_CAMERA_ID_NOT_SPECIFIED = ""
+ private const val LOGICAL_CAMERA_ID_REAR = "0"
+ private const val LOGICAL_CAMERA_ID_FRONT = "1"
+ private const val PHYSICAL_CAMERA_ID_OUTER_FRONT = "5"
+ private const val PHYSICAL_CAMERA_ID_INNER_FRONT = "6"
+ private const val PROTECTION_PATH_STRING_OUTER_FRONT =
+ "M 50,50 a 20,20 0 1 0 40,0 a 20,20 0 1 0 -40,0 Z"
+ private const val PROTECTION_PATH_STRING_INNER_FRONT =
+ "M 40,40 a 10,10 0 1 0 20,0 a 10,10 0 1 0 -20,0 Z"
+ private val PATH_RECT_FRONT =
+ rectFromPath(pathFromString(PROTECTION_PATH_STRING_OUTER_FRONT))
+ private val PATH_RECT_INNER =
+ rectFromPath(pathFromString(PROTECTION_PATH_STRING_INNER_FRONT))
private fun pathFromString(pathString: String): Path {
val spec = pathString.trim()
@@ -58,105 +62,310 @@ class CameraAvailabilityListenerTest : SysuiTestCase() {
}
}
- @Mock private lateinit var cameraManager: CameraManager
- @Mock
- private lateinit var cameraTransitionCb: CameraAvailabilityListener.CameraTransitionCallback
- private lateinit var cameraAvailabilityListener: CameraAvailabilityListener
+ @get:Rule val expect: Expect = Expect.create()
+
+ private val cameraManager = mock<CameraManager>()
+ private val cameraTransitionCallback = TestCameraTransitionCallback()
+
+ private lateinit var cameraAvailabilityCallback: CameraManager.AvailabilityCallback
@Before
fun setUp() {
- MockitoAnnotations.initMocks(this)
- context
- .getOrCreateTestableResources()
- .addOverride(R.string.config_cameraProtectionExcludedPackages, EXCLUDED_PKG)
- context
- .getOrCreateTestableResources()
- .addOverride(R.string.config_protectedCameraId, CAMERA_ID_FRONT)
- context
- .getOrCreateTestableResources()
- .addOverride(
- R.string.config_frontBuiltInDisplayCutoutProtection,
- PROTECTION_PATH_STRING_FRONT
- )
- context
- .getOrCreateTestableResources()
- .addOverride(R.string.config_protectedInnerCameraId, CAMERA_ID_INNER)
- context
- .getOrCreateTestableResources()
- .addOverride(
- R.string.config_innerBuiltInDisplayCutoutProtection,
- PROTECTION_PATH_STRING_INNER
+ overrideResource(R.string.config_cameraProtectionExcludedPackages, EXCLUDED_PKG)
+ setOuterFrontCameraId(LOGICAL_CAMERA_ID_FRONT)
+ setOuterFrontPhysicalCameraId(PHYSICAL_CAMERA_ID_OUTER_FRONT)
+ overrideResource(
+ R.string.config_frontBuiltInDisplayCutoutProtection,
+ PROTECTION_PATH_STRING_OUTER_FRONT
+ )
+ setInnerFrontCameraId(LOGICAL_CAMERA_ID_FRONT)
+ setInnerFrontPhysicalCameraId(PHYSICAL_CAMERA_ID_INNER_FRONT)
+ overrideResource(
+ R.string.config_innerBuiltInDisplayCutoutProtection,
+ PROTECTION_PATH_STRING_INNER_FRONT
+ )
+ context.addMockSystemService(CameraManager::class.java, cameraManager)
+
+ whenever(
+ cameraManager.registerAvailabilityCallback(
+ any(Executor::class.java),
+ any(CameraManager.AvailabilityCallback::class.java)
+ )
)
+ .thenAnswer {
+ cameraAvailabilityCallback = it.arguments[1] as CameraManager.AvailabilityCallback
+ return@thenAnswer Unit
+ }
+ }
- context.addMockSystemService(CameraManager::class.java, cameraManager)
+ @Test
+ fun onCameraOpened_matchesOuterFrontInfo_showsOuterProtection() {
+ setInnerFrontCameraId(LOGICAL_CAMERA_ID_NOT_SPECIFIED)
+ createAndStartSut()
- cameraAvailabilityListener =
- CameraAvailabilityListener.Factory.build(context, context.mainExecutor)
+ openCamera(LOGICAL_CAMERA_ID_FRONT)
+
+ assertOuterProtectionShowing()
}
@Test
- fun testFrontCamera() {
- var path: Path? = null
- var rect: Rect? = null
- val callback =
- object : CameraAvailabilityListener.CameraTransitionCallback {
- override fun onApplyCameraProtection(protectionPath: Path, bounds: Rect) {
- path = protectionPath
- rect = bounds
- }
+ fun onCameraOpened_matchesInnerFrontInfo_showsInnerProtection() {
+ setOuterFrontCameraId(LOGICAL_CAMERA_ID_NOT_SPECIFIED)
+ createAndStartSut()
- override fun onHideCameraProtection() {}
- }
+ openCamera(LOGICAL_CAMERA_ID_FRONT)
- cameraAvailabilityListener.addTransitionCallback(callback)
- cameraAvailabilityListener.startListening()
+ assertInnerProtectionShowing()
+ }
- val callbackCaptor = withArgCaptor {
- verify(cameraManager).registerAvailabilityCallback(any(Executor::class.java), capture())
- }
+ @Test
+ fun onCameraOpened_doesNotMatchAnyProtectionInfo_doesNotShowProtection() {
+ createAndStartSut()
- callbackCaptor.onCameraOpened(CAMERA_ID_FRONT, "")
- assertNotNull(path)
- assertEquals(PATH_RECT_FRONT, rect)
+ openCamera(LOGICAL_CAMERA_ID_REAR)
+
+ assertProtectionNotShowing()
}
@Test
- fun testInnerCamera() {
- var path: Path? = null
- var rect: Rect? = null
- val callback =
- object : CameraAvailabilityListener.CameraTransitionCallback {
- override fun onApplyCameraProtection(protectionPath: Path, bounds: Rect) {
- path = protectionPath
- rect = bounds
- }
+ fun onCameraOpened_matchesInnerAndOuter_innerUnavailable_showsOuterProtection() {
+ val dupeCameraId = "1"
+ setInnerFrontCameraId(dupeCameraId)
+ setOuterFrontCameraId(dupeCameraId)
+ createAndStartSut()
- override fun onHideCameraProtection() {}
- }
+ setPhysicalCameraUnavailable(dupeCameraId, PHYSICAL_CAMERA_ID_INNER_FRONT)
+ openCamera(dupeCameraId)
- cameraAvailabilityListener.addTransitionCallback(callback)
- cameraAvailabilityListener.startListening()
+ assertOuterProtectionShowing()
+ }
- val callbackCaptor = withArgCaptor {
- verify(cameraManager).registerAvailabilityCallback(any(Executor::class.java), capture())
- }
+ @Test
+ fun onCameraOpened_matchesInnerAndOuter_outerUnavailable_showsInnerFrontProtection() {
+ val dupeCameraId = "1"
+ setInnerFrontCameraId(dupeCameraId)
+ setOuterFrontCameraId(dupeCameraId)
+ createAndStartSut()
+
+ setPhysicalCameraUnavailable(dupeCameraId, PHYSICAL_CAMERA_ID_OUTER_FRONT)
+ openCamera(dupeCameraId)
- callbackCaptor.onCameraOpened(CAMERA_ID_INNER, "")
- assertNotNull(path)
- assertEquals(PATH_RECT_INNER, rect)
+ assertInnerProtectionShowing()
}
@Test
- fun testExcludedPackage() {
- cameraAvailabilityListener.addTransitionCallback(cameraTransitionCb)
- cameraAvailabilityListener.startListening()
+ fun onCameraOpened_matchesOuterFrontInfo_packageExcluded_doesNotShowProtection() {
+ setInnerFrontCameraId(LOGICAL_CAMERA_ID_NOT_SPECIFIED)
+ createAndStartSut()
+
+ openCamera(LOGICAL_CAMERA_ID_FRONT, EXCLUDED_PKG)
+
+ assertProtectionNotShowing()
+ }
+
+ @Test
+ fun onCameraOpened_matchesInnerFrontInfo_packageExcluded_doesNotShowProtection() {
+ setOuterFrontCameraId(LOGICAL_CAMERA_ID_NOT_SPECIFIED)
+ createAndStartSut()
+
+ openCamera(LOGICAL_CAMERA_ID_FRONT, EXCLUDED_PKG)
+
+ assertProtectionNotShowing()
+ }
+
+ @Test
+ fun onCameraClosed_matchesActiveOuterFrontProtection_hidesProtection() {
+ setInnerFrontCameraId(LOGICAL_CAMERA_ID_NOT_SPECIFIED)
+ createAndStartSut()
+ openCamera(LOGICAL_CAMERA_ID_FRONT)
+
+ closeCamera(LOGICAL_CAMERA_ID_FRONT)
+
+ assertProtectionNotShowing()
+ }
+
+ @Test
+ fun onCameraClosed_matchesActiveInnerFrontProtection_hidesProtection() {
+ setOuterFrontCameraId(LOGICAL_CAMERA_ID_NOT_SPECIFIED)
+ createAndStartSut()
+ openCamera(LOGICAL_CAMERA_ID_FRONT)
+
+ closeCamera(LOGICAL_CAMERA_ID_FRONT)
+
+ assertProtectionNotShowing()
+ }
+
+ @Test
+ fun onCameraClosed_doesNotMatchActiveOuterFrontProtection_keepsShowingProtection() {
+ setInnerFrontCameraId(LOGICAL_CAMERA_ID_NOT_SPECIFIED)
+ createAndStartSut()
+ openCamera(LOGICAL_CAMERA_ID_FRONT)
+
+ closeCamera(LOGICAL_CAMERA_ID_REAR)
+
+ assertOuterProtectionShowing()
+ }
+
+ @Test
+ fun onCameraClosed_doesNotMatchActiveInnerFrontProtection_keepsShowingProtection() {
+ setOuterFrontCameraId(LOGICAL_CAMERA_ID_NOT_SPECIFIED)
+ createAndStartSut()
+ openCamera(LOGICAL_CAMERA_ID_FRONT)
+
+ closeCamera(LOGICAL_CAMERA_ID_REAR)
+
+ assertInnerProtectionShowing()
+ }
+
+ @Test
+ fun onPhysicalCameraAvailable_cameraOpen_matchesOuterFront_showsOuterFrontProtection() {
+ val logicalCameraId = "1"
+ setOuterFrontCameraId(logicalCameraId)
+ setInnerFrontCameraId(logicalCameraId)
+ createAndStartSut()
+ setPhysicalCameraUnavailable(logicalCameraId, PHYSICAL_CAMERA_ID_OUTER_FRONT)
+ openCamera(logicalCameraId)
+
+ setPhysicalCameraAvailable(logicalCameraId, PHYSICAL_CAMERA_ID_OUTER_FRONT)
+
+ assertOuterProtectionShowing()
+ }
- val callbackCaptor = withArgCaptor {
- verify(cameraManager).registerAvailabilityCallback(any(Executor::class.java), capture())
+ @Test
+ fun onPhysicalCameraAvailable_cameraClosed_matchesOuterFront_doesNotShowProtection() {
+ val logicalCameraId = "1"
+ setOuterFrontCameraId(logicalCameraId)
+ setInnerFrontCameraId(logicalCameraId)
+ createAndStartSut()
+ setPhysicalCameraUnavailable(logicalCameraId, PHYSICAL_CAMERA_ID_OUTER_FRONT)
+
+ setPhysicalCameraAvailable(logicalCameraId, PHYSICAL_CAMERA_ID_OUTER_FRONT)
+
+ assertProtectionNotShowing()
+ }
+
+ @Test
+ fun onPhysicalCameraAvailable_cameraOpen_matchesInnerFront_showsInnerFrontProtection() {
+ val logicalCameraId = "1"
+ setOuterFrontCameraId(logicalCameraId)
+ setInnerFrontCameraId(logicalCameraId)
+ createAndStartSut()
+ setPhysicalCameraUnavailable(logicalCameraId, PHYSICAL_CAMERA_ID_INNER_FRONT)
+ openCamera(logicalCameraId)
+
+ setPhysicalCameraAvailable(logicalCameraId, PHYSICAL_CAMERA_ID_INNER_FRONT)
+
+ assertInnerProtectionShowing()
+ }
+
+ @Test
+ fun onPhysicalCameraAvailable_cameraClosed_matchesInnerFront_doesNotShowProtection() {
+ val logicalCameraId = "1"
+ setOuterFrontCameraId(logicalCameraId)
+ setInnerFrontCameraId(logicalCameraId)
+ createAndStartSut()
+ setPhysicalCameraUnavailable(logicalCameraId, PHYSICAL_CAMERA_ID_INNER_FRONT)
+
+ setPhysicalCameraAvailable(logicalCameraId, PHYSICAL_CAMERA_ID_INNER_FRONT)
+
+ assertProtectionNotShowing()
+ }
+
+ @Test
+ fun onPhysicalCameraUnavailable_matchesActiveProtection_hidesProtection() {
+ setInnerFrontCameraId(LOGICAL_CAMERA_ID_NOT_SPECIFIED)
+ createAndStartSut()
+ openCamera(LOGICAL_CAMERA_ID_FRONT)
+
+ setPhysicalCameraUnavailable(LOGICAL_CAMERA_ID_FRONT, PHYSICAL_CAMERA_ID_OUTER_FRONT)
+
+ assertProtectionNotShowing()
+ }
+
+ @Test
+ fun onPhysicalCameraUnavailable_doesNotMatchActiveProtection_keepsShowingProtection() {
+ setInnerFrontCameraId(LOGICAL_CAMERA_ID_NOT_SPECIFIED)
+ createAndStartSut()
+ openCamera(LOGICAL_CAMERA_ID_FRONT)
+
+ setPhysicalCameraUnavailable(LOGICAL_CAMERA_ID_FRONT, PHYSICAL_CAMERA_ID_INNER_FRONT)
+
+ assertOuterProtectionShowing()
+ }
+
+ private fun openCamera(logicalCameraId: String, packageId: String = "") {
+ cameraAvailabilityCallback.onCameraOpened(logicalCameraId, packageId)
+ }
+
+ private fun closeCamera(logicalCameraId: String) {
+ cameraAvailabilityCallback.onCameraClosed(logicalCameraId)
+ }
+
+ private fun setPhysicalCameraAvailable(logicalCameraId: String, physicalCameraId: String) {
+ cameraAvailabilityCallback.onPhysicalCameraAvailable(logicalCameraId, physicalCameraId)
+ }
+
+ private fun setPhysicalCameraUnavailable(logicalCameraId: String, physicalCameraId: String) {
+ cameraAvailabilityCallback.onPhysicalCameraUnavailable(logicalCameraId, physicalCameraId)
+ }
+
+ private fun assertOuterProtectionShowing() {
+ expect.that(cameraTransitionCallback.shouldShowProtection).isTrue()
+ expect.that(cameraTransitionCallback.protectionPath).isNotNull()
+ expect.that(cameraTransitionCallback.protectionBounds).isEqualTo(PATH_RECT_FRONT)
+ }
+
+ private fun assertInnerProtectionShowing() {
+ expect.that(cameraTransitionCallback.shouldShowProtection).isTrue()
+ expect.that(cameraTransitionCallback.protectionPath).isNotNull()
+ expect.that(cameraTransitionCallback.protectionBounds).isEqualTo(PATH_RECT_INNER)
+ }
+
+ private fun assertProtectionNotShowing() {
+ expect.that(cameraTransitionCallback.shouldShowProtection).isFalse()
+ expect.that(cameraTransitionCallback.protectionBounds).isNull()
+ expect.that(cameraTransitionCallback.protectionPath).isNull()
+ }
+
+ private fun setOuterFrontCameraId(id: String) {
+ overrideResource(R.string.config_protectedCameraId, id)
+ }
+
+ private fun setOuterFrontPhysicalCameraId(id: String) {
+ overrideResource(R.string.config_protectedPhysicalCameraId, id)
+ }
+
+ private fun setInnerFrontCameraId(id: String) {
+ overrideResource(R.string.config_protectedInnerCameraId, id)
+ }
+
+ private fun setInnerFrontPhysicalCameraId(id: String) {
+ overrideResource(R.string.config_protectedInnerPhysicalCameraId, id)
+ }
+
+ private fun createAndStartSut(): CameraAvailabilityListener {
+ return CameraAvailabilityListener.build(context, context.mainExecutor).also {
+ it.addTransitionCallback(cameraTransitionCallback)
+ it.startListening()
+ }
+ }
+
+ private class TestCameraTransitionCallback :
+ CameraAvailabilityListener.CameraTransitionCallback {
+ var shouldShowProtection = false
+ var protectionPath: Path? = null
+ var protectionBounds: Rect? = null
+
+ override fun onApplyCameraProtection(protectionPath: Path, bounds: Rect) {
+ shouldShowProtection = true
+ this.protectionPath = protectionPath
+ this.protectionBounds = bounds
}
- callbackCaptor.onCameraOpened(CAMERA_ID_FRONT, EXCLUDED_PKG)
- verify(cameraTransitionCb, never())
- .onApplyCameraProtection(any(Path::class.java), any(Rect::class.java))
+ override fun onHideCameraProtection() {
+ shouldShowProtection = false
+ protectionPath = null
+ protectionBounds = null
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
index fbd63c6bbdae..81424565daee 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTest.java
@@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -300,8 +301,10 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
mStateManager.onStartListening();
mStateManager.executeSetBindService(true);
mExecutor.runAllReady();
- mStateManager.onServiceDisconnected(mTileServiceComponentName);
+ mStateManager.onBindingDied(mTileServiceComponentName);
+ mExecutor.runAllReady();
mClock.advanceTime(5000);
+ mExecutor.runAllReady();
// Two calls: one for the first bind, one for the restart.
verifyBind(2);
@@ -318,20 +321,66 @@ public class TileLifecycleManagerTest extends SysuiTestCase {
mStateManager.onStartListening();
mStateManager.executeSetBindService(true);
mExecutor.runAllReady();
- mStateManager.onServiceDisconnected(mTileServiceComponentName);
+ verify(mMockTileService, times(1)).onStartListening();
+ mStateManager.onBindingDied(mTileServiceComponentName);
+ mExecutor.runAllReady();
// Longer delay than a regular one
mClock.advanceTime(5000);
- verifyBind(1);
- verify(mMockTileService, times(1)).onStartListening();
+ mExecutor.runAllReady();
+
+ assertFalse(mContext.isBound(mTileServiceComponentName));
mClock.advanceTime(20000);
+ mExecutor.runAllReady();
// Two calls: one for the first bind, one for the restart.
verifyBind(2);
verify(mMockTileService, times(2)).onStartListening();
}
@Test
+ public void testOnServiceDisconnectedDoesnUnbind_doesntForwardToBinder() throws Exception {
+ mStateManager.executeSetBindService(true);
+ mExecutor.runAllReady();
+
+ mStateManager.onStartListening();
+ verify(mMockTileService).onStartListening();
+
+ clearInvocations(mMockTileService);
+ mStateManager.onServiceDisconnected(mTileServiceComponentName);
+ mExecutor.runAllReady();
+
+ mStateManager.onStartListening();
+ verify(mMockTileService, never()).onStartListening();
+ }
+
+ @Test
+ public void testKillProcessLowMemory_unbound_doesntBindAgain() throws Exception {
+ doAnswer(invocation -> {
+ ActivityManager.MemoryInfo memoryInfo = invocation.getArgument(0);
+ memoryInfo.lowMemory = true;
+ return null;
+ }).when(mActivityManager).getMemoryInfo(any());
+ mStateManager.onStartListening();
+ mStateManager.executeSetBindService(true);
+ mExecutor.runAllReady();
+ verifyBind(1);
+ verify(mMockTileService, times(1)).onStartListening();
+
+ mStateManager.onBindingDied(mTileServiceComponentName);
+ mExecutor.runAllReady();
+
+ clearInvocations(mMockTileService);
+ mStateManager.executeSetBindService(false);
+ mExecutor.runAllReady();
+ mClock.advanceTime(30000);
+ mExecutor.runAllReady();
+
+ verifyBind(0);
+ verify(mMockTileService, never()).onStartListening();
+ }
+
+ @Test
public void testToggleableTile() throws Exception {
assertTrue(mStateManager.isToggleableTile());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt
index 313ccb8a8717..154aa1cabb0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogTest.kt
@@ -23,6 +23,8 @@ import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
+import android.view.ViewGroup.LayoutParams.MATCH_PARENT
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.test.filters.SmallTest
@@ -54,6 +56,7 @@ class BluetoothTileDialogTest : SysuiTestCase() {
const val DEVICE_NAME = "device"
const val DEVICE_CONNECTION_SUMMARY = "active"
const val ENABLED = true
+ const val CONTENT_HEIGHT = WRAP_CONTENT
}
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
@@ -88,6 +91,7 @@ class BluetoothTileDialogTest : SysuiTestCase() {
BluetoothTileDialog(
ENABLED,
subtitleResId,
+ CONTENT_HEIGHT,
bluetoothTileDialogCallback,
dispatcher,
fakeSystemClock,
@@ -116,9 +120,9 @@ class BluetoothTileDialogTest : SysuiTestCase() {
assertThat(bluetoothTileDialog.isShowing).isTrue()
assertThat(recyclerView).isNotNull()
- assertThat(recyclerView?.visibility).isEqualTo(VISIBLE)
- assertThat(recyclerView?.adapter).isNotNull()
- assertThat(recyclerView?.layoutManager is LinearLayoutManager).isTrue()
+ assertThat(recyclerView.visibility).isEqualTo(VISIBLE)
+ assertThat(recyclerView.adapter).isNotNull()
+ assertThat(recyclerView.layoutManager is LinearLayoutManager).isTrue()
}
@Test
@@ -128,6 +132,7 @@ class BluetoothTileDialogTest : SysuiTestCase() {
BluetoothTileDialog(
ENABLED,
subtitleResId,
+ CONTENT_HEIGHT,
bluetoothTileDialogCallback,
dispatcher,
fakeSystemClock,
@@ -144,7 +149,7 @@ class BluetoothTileDialogTest : SysuiTestCase() {
)
val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list)
- val adapter = recyclerView?.adapter as BluetoothTileDialog.Adapter
+ val adapter = recyclerView.adapter as BluetoothTileDialog.Adapter
assertThat(adapter.itemCount).isEqualTo(1)
assertThat(adapter.getItem(0).deviceName).isEqualTo(DEVICE_NAME)
assertThat(adapter.getItem(0).connectionSummary).isEqualTo(DEVICE_CONNECTION_SUMMARY)
@@ -162,6 +167,7 @@ class BluetoothTileDialogTest : SysuiTestCase() {
BluetoothTileDialog(
ENABLED,
subtitleResId,
+ CONTENT_HEIGHT,
bluetoothTileDialogCallback,
dispatcher,
fakeSystemClock,
@@ -189,6 +195,7 @@ class BluetoothTileDialogTest : SysuiTestCase() {
BluetoothTileDialog(
ENABLED,
subtitleResId,
+ CONTENT_HEIGHT,
bluetoothTileDialogCallback,
dispatcher,
fakeSystemClock,
@@ -213,6 +220,7 @@ class BluetoothTileDialogTest : SysuiTestCase() {
BluetoothTileDialog(
ENABLED,
subtitleResId,
+ CONTENT_HEIGHT,
bluetoothTileDialogCallback,
dispatcher,
fakeSystemClock,
@@ -232,13 +240,38 @@ class BluetoothTileDialogTest : SysuiTestCase() {
val pairNewButton =
bluetoothTileDialog.requireViewById<View>(R.id.pair_new_device_button)
val recyclerView = bluetoothTileDialog.requireViewById<RecyclerView>(R.id.device_list)
- val adapter = recyclerView?.adapter as BluetoothTileDialog.Adapter
+ val adapter = recyclerView.adapter as BluetoothTileDialog.Adapter
+ val scrollViewContent = bluetoothTileDialog.requireViewById<View>(R.id.scroll_view)
assertThat(seeAllButton).isNotNull()
assertThat(seeAllButton.visibility).isEqualTo(GONE)
assertThat(pairNewButton).isNotNull()
assertThat(pairNewButton.visibility).isEqualTo(VISIBLE)
assertThat(adapter.itemCount).isEqualTo(1)
+ assertThat(scrollViewContent.layoutParams.height).isEqualTo(WRAP_CONTENT)
+ }
+ }
+
+ @Test
+ fun testShowDialog_displayFromCachedHeight() {
+ testScope.runTest {
+ bluetoothTileDialog =
+ BluetoothTileDialog(
+ ENABLED,
+ subtitleResId,
+ MATCH_PARENT,
+ bluetoothTileDialogCallback,
+ dispatcher,
+ fakeSystemClock,
+ uiEventLogger,
+ logger,
+ mContext
+ )
+ bluetoothTileDialog.show()
+ assertThat(
+ bluetoothTileDialog.requireViewById<View>(R.id.scroll_view).layoutParams.height
+ )
+ .isEqualTo(MATCH_PARENT)
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
index 99993f2b3eff..33066d2092b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/bluetooth/BluetoothTileDialogViewModelTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.dialog.bluetooth
+import android.content.SharedPreferences
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
@@ -78,6 +79,8 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
@Mock private lateinit var logger: BluetoothTileDialogLogger
+ @Mock private lateinit var sharedPreferences: SharedPreferences
+
private lateinit var scheduler: TestCoroutineScheduler
private lateinit var dispatcher: CoroutineDispatcher
private lateinit var testScope: TestScope
@@ -98,6 +101,8 @@ class BluetoothTileDialogViewModelTest : SysuiTestCase() {
logger,
testScope.backgroundScope,
dispatcher,
+ dispatcher,
+ sharedPreferences,
)
`when`(deviceItemInteractor.deviceItemUpdate).thenReturn(MutableSharedFlow())
`when`(bluetoothStateInteractor.bluetoothStateUpdate)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
new file mode 100644
index 000000000000..5569ca9520e9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.testing.ViewUtils
+import android.view.MotionEvent
+import android.view.View
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.communal.data.repository.FakeCommunalRepository
+import com.android.systemui.communal.domain.interactor.CommunalInteractor
+import com.android.systemui.communal.domain.interactor.CommunalInteractorFactory
+import com.android.systemui.communal.shared.model.CommunalSceneKey
+import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
+import com.android.systemui.compose.ComposeFacade
+import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
+import com.android.systemui.res.R
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import org.junit.Assert.assertThrows
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.BeforeClass
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+@SmallTest
+class GlanceableHubContainerControllerTest : SysuiTestCase() {
+ @Mock private lateinit var communalViewModel: CommunalViewModel
+ @Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
+ @Mock private lateinit var shadeInteractor: ShadeInteractor
+
+ private lateinit var containerView: View
+ private lateinit var testableLooper: TestableLooper
+
+ private lateinit var communalInteractor: CommunalInteractor
+ private lateinit var communalRepository: FakeCommunalRepository
+ private lateinit var underTest: GlanceableHubContainerController
+
+ private val bouncerShowingFlow = MutableStateFlow(false)
+ private val shadeShowingFlow = MutableStateFlow(false)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ val withDeps = CommunalInteractorFactory.create()
+ communalInteractor = withDeps.communalInteractor
+ communalRepository = withDeps.communalRepository
+
+ underTest =
+ GlanceableHubContainerController(
+ communalInteractor,
+ communalViewModel,
+ keyguardTransitionInteractor,
+ shadeInteractor
+ )
+ testableLooper = TestableLooper.get(this)
+
+ communalRepository.setIsCommunalEnabled(true)
+
+ whenever(keyguardTransitionInteractor.isFinishedInStateWhere(any()))
+ .thenReturn(bouncerShowingFlow)
+ whenever(shadeInteractor.isAnyFullyExpanded).thenReturn(shadeShowingFlow)
+
+ overrideResource(R.dimen.communal_grid_gutter_size, SWIPE_REGION_WIDTH)
+ }
+
+ @Test
+ fun isEnabled_interactorEnabled_returnsTrue() {
+ communalRepository.setIsCommunalEnabled(true)
+
+ assertThat(underTest.isEnabled()).isTrue()
+ }
+
+ @Test
+ fun isEnabled_interactorDisabled_returnsFalse() {
+ communalRepository.setIsCommunalEnabled(false)
+
+ assertThat(underTest.isEnabled()).isFalse()
+ }
+
+ @Test
+ fun initView_notEnabled_throwsException() {
+ communalRepository.setIsCommunalEnabled(false)
+
+ assertThrows(RuntimeException::class.java) { underTest.initView(context) }
+ }
+
+ @Test
+ fun initView_calledTwice_throwsException() {
+ // First call succeeds.
+ underTest.initView(context)
+
+ // Second call throws.
+ assertThrows(RuntimeException::class.java) { underTest.initView(context) }
+ }
+
+ @Test
+ fun onTouchEvent_touchInsideGestureRegion_returnsTrue() {
+ // Communal is open.
+ communalRepository.setDesiredScene(CommunalSceneKey.Communal)
+
+ initAndAttachContainerView()
+
+ // Touch events are intercepted.
+ assertThat(underTest.onTouchEvent(DOWN_IN_SWIPE_REGION_EVENT)).isTrue()
+ }
+
+ @Test
+ fun onTouchEvent_subsequentTouchesAfterGestureStart_returnsTrue() {
+ // Communal is open.
+ communalRepository.setDesiredScene(CommunalSceneKey.Communal)
+
+ initAndAttachContainerView()
+
+ // Initial touch down is intercepted, and so are touches outside of the region, until an up
+ // event is received.
+ assertThat(underTest.onTouchEvent(DOWN_IN_SWIPE_REGION_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(UP_EVENT)).isTrue()
+ assertThat(underTest.onTouchEvent(MOVE_EVENT)).isFalse()
+ }
+
+ @Test
+ fun onTouchEvent_communalOpen_returnsTrue() {
+ // Communal is open.
+ communalRepository.setDesiredScene(CommunalSceneKey.Communal)
+
+ initAndAttachContainerView()
+ testableLooper.processAllMessages()
+
+ // Touch events are intercepted.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ }
+
+ @Test
+ fun onTouchEvent_communalAndBouncerShowing_returnsFalse() {
+ // Communal is open.
+ communalRepository.setDesiredScene(CommunalSceneKey.Communal)
+
+ initAndAttachContainerView()
+
+ // Bouncer is visible.
+ bouncerShowingFlow.value = true
+ testableLooper.processAllMessages()
+
+ // Touch events are not intercepted.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ }
+
+ @Test
+ fun onTouchEvent_communalAndShadeShowing_returnsFalse() {
+ // Communal is open.
+ communalRepository.setDesiredScene(CommunalSceneKey.Communal)
+
+ initAndAttachContainerView()
+
+ shadeShowingFlow.value = true
+ testableLooper.processAllMessages()
+
+ // Touch events are not intercepted.
+ assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ }
+
+ private fun initAndAttachContainerView() {
+ containerView = View(context)
+ // Make view clickable so that dispatchTouchEvent returns true.
+ containerView.isClickable = true
+
+ underTest.initView(containerView)
+ // Attach the view so that flows start collecting.
+ ViewUtils.attachView(containerView)
+ // Give the view a size so that determining if a touch starts at the right edge works.
+ containerView.layout(0, 0, CONTAINER_WIDTH, CONTAINER_HEIGHT)
+ }
+
+ companion object {
+ private const val CONTAINER_WIDTH = 100
+ private const val CONTAINER_HEIGHT = 100
+ private const val SWIPE_REGION_WIDTH = 20
+
+ private val DOWN_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+ private val DOWN_IN_SWIPE_REGION_EVENT =
+ MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, CONTAINER_WIDTH.toFloat(), 0f, 0)
+ private val MOVE_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
+ private val UP_EVENT = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0f, 0f, 0)
+
+ @BeforeClass
+ @JvmStatic
+ fun beforeClass() {
+ // Glanceable hub requires Compose, no point running any of these tests if compose isn't
+ // enabled.
+ assumeTrue(ComposeFacade.isComposeAvailable())
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 6ff79660efec..9d997dae6836 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade
+import android.content.Context
import android.os.Handler
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
@@ -45,8 +46,6 @@ import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollectorFake
-import com.android.systemui.communal.data.repository.FakeCommunalRepository
-import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.compose.ComposeFacade.isComposeAvailable
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
@@ -98,6 +97,7 @@ import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
+import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.test.TestScope
@@ -112,9 +112,8 @@ import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-import java.util.Optional
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@@ -150,8 +149,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
@Mock
private lateinit var mLockscreenHostedDreamGestureListener: LockscreenHostedDreamGestureListener
@Mock private lateinit var notificationInsetsController: NotificationInsetsController
- @Mock private lateinit var mCommunalViewModel: CommunalViewModel
- private lateinit var mCommunalRepository: FakeCommunalRepository
+ @Mock private lateinit var mGlanceableHubContainerController: GlanceableHubContainerController
@Mock lateinit var keyguardBouncerComponentFactory: KeyguardBouncerComponent.Factory
@Mock lateinit var keyguardBouncerComponent: KeyguardBouncerComponent
@Mock lateinit var keyguardSecurityContainerController: KeyguardSecurityContainerController
@@ -201,8 +199,6 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
featureFlagsClassic.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false)
mSetFlagsRule.disableFlags(Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR)
- mCommunalRepository = FakeCommunalRepository()
-
testScope = TestScope()
fakeClock = FakeSystemClock()
underTest =
@@ -236,8 +232,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
mock(KeyguardMessageAreaController.Factory::class.java),
keyguardTransitionInteractor,
primaryBouncerToGoneTransitionViewModel,
- mCommunalViewModel,
- mCommunalRepository,
+ mGlanceableHubContainerController,
notificationLaunchAnimationInteractor,
featureFlagsClassic,
fakeClock,
@@ -466,6 +461,16 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
}
@Test
+ fun handleDispatchTouchEvent_glanceableHubIntercepts_returnsTrue() {
+ whenever(mGlanceableHubContainerController.onTouchEvent(DOWN_EVENT)).thenReturn(true)
+ underTest.setStatusBarViewController(phoneStatusBarViewController)
+
+ val returnVal = interactionEventHandler.handleDispatchTouchEvent(DOWN_EVENT)
+
+ assertThat(returnVal).isTrue()
+ }
+
+ @Test
fun shouldInterceptTouchEvent_statusBarKeyguardViewManagerShouldIntercept() {
// down event should be intercepted by keyguardViewManager
whenever(statusBarKeyguardViewManager.shouldInterceptTouchEvent(DOWN_EVENT))
@@ -546,7 +551,11 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
return
}
- mCommunalRepository.setIsCommunalEnabled(true)
+ whenever(mGlanceableHubContainerController.isEnabled()).thenReturn(true)
+
+ val mockCommunalView = mock(View::class.java)
+ whenever(mGlanceableHubContainerController.initView(any<Context>()))
+ .thenReturn(mockCommunalView)
val mockCommunalPlaceholder = mock(View::class.java)
val fakeViewIndex = 20
@@ -558,7 +567,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
// Communal view added as a child of the container at the proper index, the stub is removed.
verify(view).removeView(mockCommunalPlaceholder)
- verify(view).addView(any(), eq(fakeViewIndex))
+ verify(view).addView(eq(mockCommunalView), eq(fakeViewIndex))
}
@Test
@@ -567,7 +576,7 @@ class NotificationShadeWindowViewControllerTest : SysuiTestCase() {
return
}
- mCommunalRepository.setIsCommunalEnabled(false)
+ whenever(mGlanceableHubContainerController.isEnabled()).thenReturn(false)
val mockCommunalPlaceholder = mock(View::class.java)
val fakeViewIndex = 20
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 29b1366eb6c1..9750f60c7b19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -41,8 +41,6 @@ import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.bouncer.ui.viewmodel.KeyguardBouncerViewModel
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.classifier.FalsingCollectorFake
-import com.android.systemui.communal.data.repository.FakeCommunalRepository
-import com.android.systemui.communal.ui.viewmodel.CommunalViewModel
import com.android.systemui.dock.DockManager
import com.android.systemui.dump.DumpManager
import com.android.systemui.dump.logcatLogBuffer
@@ -142,8 +140,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
private lateinit var unfoldTransitionProgressProvider:
Optional<UnfoldTransitionProgressProvider>
@Mock private lateinit var notificationInsetsController: NotificationInsetsController
- @Mock private lateinit var mCommunalViewModel: CommunalViewModel
- private lateinit var mCommunalRepository: FakeCommunalRepository
+ @Mock private lateinit var mGlanceableHubContainerController: GlanceableHubContainerController
@Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
@Mock lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@@ -180,8 +177,6 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
whenever(keyguardTransitionInteractor.lockscreenToDreamingTransition)
.thenReturn(emptyFlow())
- mCommunalRepository = FakeCommunalRepository()
-
val featureFlags = FakeFeatureFlags()
featureFlags.set(Flags.TRACKPAD_GESTURE_COMMON, true)
featureFlags.set(Flags.TRACKPAD_GESTURE_FEATURES, false)
@@ -221,8 +216,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
Mockito.mock(KeyguardMessageAreaController.Factory::class.java),
keyguardTransitionInteractor,
primaryBouncerToGoneTransitionViewModel,
- mCommunalViewModel,
- mCommunalRepository,
+ mGlanceableHubContainerController,
NotificationLaunchAnimationInteractor(NotificationLaunchAnimationRepository()),
featureFlags,
FakeSystemClock(),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorInversionRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorInversionRepository.kt
new file mode 100644
index 000000000000..9a3b9e2cc701
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/accessibility/data/repository/FakeColorInversionRepository.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.accessibility.data.repository
+
+import android.os.UserHandle
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+
+class FakeColorInversionRepository : ColorInversionRepository {
+ private val userMap = mutableMapOf<Int, MutableStateFlow<Boolean>>()
+
+ override fun isEnabled(userHandle: UserHandle): StateFlow<Boolean> {
+ return getFlow(userHandle.identifier)
+ }
+
+ override suspend fun setIsEnabled(isEnabled: Boolean, userHandle: UserHandle): Boolean {
+ getFlow(userHandle.identifier).value = isEnabled
+ return true
+ }
+
+ /** initializes the flow if already not */
+ private fun getFlow(userId: Int): MutableStateFlow<Boolean> {
+ return userMap.getOrPut(userId) { MutableStateFlow(false) }
+ }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/inversion/ColorInversionTileKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/inversion/ColorInversionTileKosmos.kt
new file mode 100644
index 000000000000..fad34aab05e0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/impl/inversion/ColorInversionTileKosmos.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles.impl.inversion
+
+import com.android.systemui.accessibility.qs.QSAccessibilityModule
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.qs.qsEventLogger
+
+val Kosmos.qsColorInversionTileConfig by
+ Kosmos.Fixture { QSAccessibilityModule.provideColorInversionTileConfig(qsEventLogger) }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index a4b28967e3b2..77a5e3db2aba 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -72,7 +72,6 @@ import android.content.pm.ServiceInfo;
import android.content.pm.ShortcutServiceInternal;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
-import android.content.pm.UserPackage;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -560,11 +559,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(appUserId);
} else if (provider.maskedBySuspendedPackage) {
showBadge = mUserManager.hasBadge(appUserId);
- final UserPackage suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
+ final String suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
appInfo.packageName, appUserId);
// TODO(b/281839596): don't rely on platform always meaning suspended by admin.
- if (suspendingPackage != null
- && PLATFORM_PACKAGE_NAME.equals(suspendingPackage.packageName)) {
+ if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
onClickIntent = mDevicePolicyManagerInternal.createShowAdminSupportIntent(
appUserId, true);
} else {
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index cac2efba1c89..136692eb90d5 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -289,11 +289,11 @@ public abstract class PackageManagerInternal {
*
* @param suspendedPackage The package that has been suspended.
* @param userId The user for which to check.
- * @return User id and package name of the package that suspended the given package. Returns
- * {@code null} if the given package is not currently suspended and the platform package name
- * - i.e. {@code "android"} - if the package was suspended by a device admin.
+ * @return Name of the package that suspended the given package. Returns {@code null} if the
+ * given package is not currently suspended and the platform package name - i.e.
+ * {@code "android"} - if the package was suspended by a device admin.
*/
- public abstract UserPackage getSuspendingPackage(String suspendedPackage, int userId);
+ public abstract String getSuspendingPackage(String suspendedPackage, int userId);
/**
* Suspend or unsuspend packages upon admin request.
@@ -312,13 +312,13 @@ public abstract class PackageManagerInternal {
* suspended application.
*
* @param suspendedPackage The package that has been suspended.
- * @param suspendingPackage The package responsible for suspension.
+ * @param suspendingPackage
* @param userId The user for which to check.
* @return A {@link SuspendDialogInfo} object describing the dialog to be shown.
*/
@Nullable
public abstract SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
- UserPackage suspendingPackage, int userId);
+ String suspendingPackage, int userId);
/**
* Gets any distraction flags set via
@@ -1168,14 +1168,14 @@ public abstract class PackageManagerInternal {
public abstract void clearBlockUninstallForUser(@UserIdInt int userId);
/**
- * Unsuspends all packages suspended by an admin for the user.
+ * Unsuspends all packages suspended by the given package for the user.
*/
- public abstract void unsuspendAdminSuspendedPackages(int userId);
+ public abstract void unsuspendForSuspendingPackage(String suspendingPackage, int userId);
/**
- * Returns {@code true} if an admin is suspending any packages for the user.
+ * Returns {@code true} if the package is suspending any packages for the user.
*/
- public abstract boolean isAdminSuspendingAnyPackages(int userId);
+ public abstract boolean isSuspendingAnyPackages(String suspendingPackage, int userId);
/**
* Register to listen for loading progress of an installed package.
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index c436c7217d0f..fd17261bda41 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -136,6 +136,7 @@ public class Watchdog implements Dumpable {
"media.swcodec", // /apex/com.android.media.swcodec/bin/mediaswcodec
"media.transcoding", // Media transcoding service
"com.android.bluetooth", // Bluetooth service
+ "/apex/com.android.art/bin/artd", // ART daemon
"/apex/com.android.os.statsd/bin/statsd", // Stats daemon
};
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2ee39c577977..a80d2fd32593 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2085,7 +2085,6 @@ public class ActivityManagerService extends IActivityManager.Stub
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
app.mProfile.addHostingComponentType(HOSTING_COMPONENT_TYPE_SYSTEM);
addPidLocked(app);
- mOomAdjuster.onProcessBeginLocked(app);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked(OOM_ADJ_REASON_SYSTEM_INIT);
}
@@ -4624,7 +4623,6 @@ public class ActivityManagerService extends IActivityManager.Stub
EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
synchronized (mProcLock) {
- mOomAdjuster.onProcessBeginLocked(app);
mOomAdjuster.setAttachingProcessStatesLSP(app);
clearProcessForegroundLocked(app);
app.setDebugging(false);
@@ -7104,7 +7102,6 @@ public class ActivityManagerService extends IActivityManager.Stub
sdkSandboxClientAppPackage,
new HostingRecord(HostingRecord.HOSTING_TYPE_ADDED_APPLICATION,
customProcess != null ? customProcess : info.processName));
- mOomAdjuster.onProcessBeginLocked(app);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked(app, OOM_ADJ_REASON_PROCESS_BEGIN);
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index b00dcd6ccf1f..3424578a78d2 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -41,7 +41,6 @@ import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
-import static android.app.ActivityManager.PROCESS_STATE_UNKNOWN;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ACTIVITY;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_ALLOWLIST;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_BACKUP;
@@ -3494,8 +3493,8 @@ public class OomAdjuster {
int initialCapability = PROCESS_CAPABILITY_NONE;
boolean initialCached = true;
final ProcessStateRecord state = app.mState;
- final int prevProcState = PROCESS_STATE_UNKNOWN;
- final int prevAdj = UNKNOWN_ADJ;
+ final int prevProcState = state.getCurRawProcState();
+ final int prevAdj = state.getCurRawAdj();
// If the process has been marked as foreground, it is starting as the top app (with
// Zygote#START_AS_TOP_APP_ARG), so boost the thread priority of its default UI thread.
if (state.hasForegroundActivities()) {
@@ -3782,11 +3781,6 @@ public class OomAdjuster {
}
@GuardedBy("mService")
- void onProcessBeginLocked(@NonNull ProcessRecord app) {
- // Empty, the OomAdjusterModernImpl will have an implementation.
- }
-
- @GuardedBy("mService")
void onProcessEndLocked(@NonNull ProcessRecord app) {
// Empty, the OomAdjusterModernImpl will have an implementation.
}
diff --git a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
index d372108e0a47..7cc7c517fa9c 100644
--- a/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
+++ b/services/core/java/com/android/server/am/OomAdjusterModernImpl.java
@@ -331,9 +331,9 @@ public class OomAdjusterModernImpl extends OomAdjuster {
if (mLastNode[prevSlot] == node) {
mLastNode[prevSlot] = node.mPrev;
}
- node.unlink();
}
- mProcessRecordNodes[newSlot].append(node);
+ // node will be firstly unlinked in the append.
+ append(node, newSlot);
}
void moveAllNodesTo(int fromSlot, int toSlot) {
@@ -389,7 +389,11 @@ public class OomAdjusterModernImpl extends OomAdjuster {
}
void append(@NonNull ProcessRecord app, int targetSlot) {
- final ProcessRecordNode node = app.mLinkedNodes[mType];
+ append(app.mLinkedNodes[mType], targetSlot);
+ }
+
+ void append(@NonNull ProcessRecordNode node, int targetSlot) {
+ node.unlink();
mProcessRecordNodes[targetSlot].append(node);
}
@@ -452,6 +456,9 @@ public class OomAdjusterModernImpl extends OomAdjuster {
@VisibleForTesting
void reset() {
+ if (HEAD.mNext != TAIL) {
+ HEAD.mNext.mPrev = TAIL.mPrev.mNext = null;
+ }
HEAD.mNext = TAIL;
TAIL.mPrev = HEAD;
}
@@ -558,20 +565,6 @@ public class OomAdjusterModernImpl extends OomAdjuster {
@GuardedBy("mService")
@Override
- void onProcessBeginLocked(@NonNull ProcessRecord app) {
- // Check one type should be good enough.
- if (app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE] == null) {
- for (int i = 0; i < app.mLinkedNodes.length; i++) {
- app.mLinkedNodes[i] = new ProcessRecordNode(app);
- }
- }
- if (!app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE].isLinked()) {
- linkProcessRecordToList(app);
- }
- }
-
- @GuardedBy("mService")
- @Override
void onProcessEndLocked(@NonNull ProcessRecord app) {
if (app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE] != null
&& app.mLinkedNodes[ProcessRecordNode.NODE_TYPE_PROC_STATE].isLinked()) {
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 40b1de623336..1412259abf89 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -299,6 +299,11 @@ class ProcessErrorStateRecord {
SparseBooleanArray lastPids = new SparseBooleanArray(20);
ActivityManagerService.VolatileDropboxEntryStates volatileDropboxEntriyStates = null;
+ if (mApp.isDebugging()) {
+ Slog.i(TAG, "Skipping debugged app ANR: " + this + " " + annotation);
+ return;
+ }
+
mApp.getWindowProcessController().appEarlyNotResponding(annotation, () -> {
latencyTracker.waitingOnAMSLockStarted();
synchronized (mService) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 3156e9da0ae9..e57206ef9bc4 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2153,6 +2153,7 @@ public final class ProcessList {
mService.forceStopPackageLocked(app.info.packageName,
UserHandle.getAppId(app.uid),
false, false, true, false, false, false, app.userId, "start failure");
+ app.doEarlyCleanupIfNecessaryLocked();
}
}
};
@@ -2782,6 +2783,7 @@ public final class ProcessList {
}
noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_INVALID_START, reason);
+ app.doEarlyCleanupIfNecessaryLocked();
return false;
}
mService.mBatteryStatsService.noteProcessStart(app.processName, app.info.uid);
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b4cd6a31291e..e5c4a66562c3 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -621,6 +621,34 @@ class ProcessRecord implements WindowProcessListener {
mWindowProcessController = new WindowProcessController(
mService.mActivityTaskManager, info, processName, uid, userId, this, this);
mPkgList.put(_info.packageName, new ProcessStats.ProcessStateHolder(_info.longVersionCode));
+ updateProcessRecordNodes(this);
+ }
+
+ /**
+ * Helper function to let test cases update the pointers.
+ */
+ @VisibleForTesting
+ static void updateProcessRecordNodes(@NonNull ProcessRecord app) {
+ if (app.mService.mConstants.ENABLE_NEW_OOMADJ) {
+ for (int i = 0; i < app.mLinkedNodes.length; i++) {
+ app.mLinkedNodes[i] = new ProcessRecordNode(app);
+ }
+ }
+ }
+
+ /**
+ * Perform cleanups if the process record is going to be discarded in an early
+ * stage of the process lifecycle, specifically when the process has not even
+ * attached itself to the system_server.
+ */
+ @GuardedBy("mService")
+ void doEarlyCleanupIfNecessaryLocked() {
+ if (getThread() == null) {
+ // It's not even attached, make sure we unlink its process nodes.
+ mService.mOomAdjuster.onProcessEndLocked(this);
+ } else {
+ // Let the binder died callback handle the cleanup.
+ }
}
void resetCrashingOnRestart() {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 290bb7e92c69..0c782318fe89 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -4505,13 +4505,13 @@ public class AudioService extends IAudioService.Stub
private void dumpFlags(PrintWriter pw) {
pw.println("\nFun with Flags: ");
- pw.println("\tandroid.media.audio.Flags.autoPublicVolumeApiHardening:"
+ pw.println("\tandroid.media.audio.autoPublicVolumeApiHardening:"
+ autoPublicVolumeApiHardening());
- pw.println("\tandroid.media.audio.Flags.focusFreezeTestApi:"
+ pw.println("\tandroid.media.audio.focusFreezeTestApi:"
+ focusFreezeTestApi());
- pw.println("\tcom.android.media.audio.Flags.bluetoothMacAddressAnonymization:"
+ pw.println("\tcom.android.media.audio.bluetoothMacAddressAnonymization:"
+ bluetoothMacAddressAnonymization());
- pw.println("\tcom.android.media.audio.Flags.disablePrescaleAbsoluteVolume:"
+ pw.println("\tcom.android.media.audio.disablePrescaleAbsoluteVolume:"
+ disablePrescaleAbsoluteVolume());
}
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index b5846b555747..a40dd7919402 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -252,9 +252,6 @@ public final class CompatChange extends CompatibilityChangeInfo {
// If the change is gated by a platform version newer than the one currently installed
// on the device, disregard the app's target sdk version.
int compareSdk = Math.min(app.targetSdkVersion, buildClassifier.platformTargetSdk());
- if (compareSdk != app.targetSdkVersion) {
- compareSdk = app.targetSdkVersion;
- }
return compareSdk >= getEnableSinceTargetSdk();
}
return true;
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index b54289321e89..2314bb772494 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -16,6 +16,8 @@
package com.android.server.display;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
@@ -40,6 +42,7 @@ import android.os.Trace;
import android.util.EventLog;
import android.util.MathUtils;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TimeUtils;
import com.android.internal.annotations.VisibleForTesting;
@@ -49,6 +52,8 @@ import com.android.server.EventLogTags;
import com.android.server.display.brightness.BrightnessEvent;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Manages the associated display brightness when in auto-brightness mode. This is also
@@ -64,6 +69,16 @@ public class AutomaticBrightnessController {
public static final int AUTO_BRIGHTNESS_DISABLED = 2;
public static final int AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE = 3;
+ @IntDef(prefix = { "AUTO_BRIGHTNESS_MODE_" }, value = {
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ AUTO_BRIGHTNESS_MODE_IDLE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AutomaticBrightnessMode{}
+
+ public static final int AUTO_BRIGHTNESS_MODE_DEFAULT = 0;
+ public static final int AUTO_BRIGHTNESS_MODE_IDLE = 1;
+
// How long the current sensor reading is assumed to be valid beyond the current time.
// This provides a bit of prediction, as well as ensures that the weight for the last sample is
// non-zero, which in turn ensures that the total weight is non-zero.
@@ -91,10 +106,11 @@ public class AutomaticBrightnessController {
private final Sensor mLightSensor;
// The mapper to translate ambient lux to screen brightness in the range [0, 1.0].
- @Nullable
+ @NonNull
private BrightnessMappingStrategy mCurrentBrightnessMapper;
- private final BrightnessMappingStrategy mInteractiveModeBrightnessMapper;
- private final BrightnessMappingStrategy mIdleModeBrightnessMapper;
+
+ // A map of Brightness Mapping Strategies indexed by AutomaticBrightnessMode
+ private final SparseArray<BrightnessMappingStrategy> mBrightnessMappingStrategyMap;
// The minimum and maximum screen brightnesses.
private final float mScreenBrightnessRangeMinimum;
@@ -251,7 +267,7 @@ public class AutomaticBrightnessController {
AutomaticBrightnessController(Callbacks callbacks, Looper looper,
SensorManager sensorManager, Sensor lightSensor,
- BrightnessMappingStrategy interactiveModeBrightnessMapper,
+ SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap,
int lightSensorWarmUpTime, float brightnessMin, float brightnessMax,
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
@@ -261,26 +277,25 @@ public class AutomaticBrightnessController {
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
BrightnessRangeController brightnessModeController,
- BrightnessThrottler brightnessThrottler,
- BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
- int ambientLightHorizonLong, float userLux, float userBrightness) {
+ BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
+ int ambientLightHorizonLong, float userLux, float userNits) {
this(new Injector(), callbacks, looper, sensorManager, lightSensor,
- interactiveModeBrightnessMapper,
- lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
- lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
- darkeningLightDebounceConfig, brighteningLightDebounceConfigIdle,
- darkeningLightDebounceConfigIdle, resetAmbientLuxAfterWarmUpConfig,
- ambientBrightnessThresholds, screenBrightnessThresholds,
- ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, context,
- brightnessModeController, brightnessThrottler, idleModeBrightnessMapper,
- ambientLightHorizonShort, ambientLightHorizonLong, userLux, userBrightness
+ brightnessMappingStrategyMap, lightSensorWarmUpTime, brightnessMin, brightnessMax,
+ dozeScaleFactor, lightSensorRate, initialLightSensorRate,
+ brighteningLightDebounceConfig, darkeningLightDebounceConfig,
+ brighteningLightDebounceConfigIdle, darkeningLightDebounceConfigIdle,
+ resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds,
+ screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
+ screenBrightnessThresholdsIdle, context, brightnessModeController,
+ brightnessThrottler, ambientLightHorizonShort, ambientLightHorizonLong, userLux,
+ userNits
);
}
@VisibleForTesting
AutomaticBrightnessController(Injector injector, Callbacks callbacks, Looper looper,
SensorManager sensorManager, Sensor lightSensor,
- BrightnessMappingStrategy interactiveModeBrightnessMapper,
+ SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap,
int lightSensorWarmUpTime, float brightnessMin, float brightnessMax,
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
@@ -290,15 +305,14 @@ public class AutomaticBrightnessController {
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
BrightnessRangeController brightnessModeController,
- BrightnessThrottler brightnessThrottler,
- BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
- int ambientLightHorizonLong, float userLux, float userBrightness) {
+ BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
+ int ambientLightHorizonLong, float userLux, float userNits) {
mInjector = injector;
mClock = injector.createClock();
mContext = context;
mCallbacks = callbacks;
mSensorManager = sensorManager;
- mCurrentBrightnessMapper = interactiveModeBrightnessMapper;
+ mCurrentBrightnessMapper = brightnessMappingStrategyMap.get(AUTO_BRIGHTNESS_MODE_DEFAULT);
mScreenBrightnessRangeMinimum = brightnessMin;
mScreenBrightnessRangeMaximum = brightnessMax;
mLightSensorWarmUpTimeConfig = lightSensorWarmUpTime;
@@ -337,13 +351,12 @@ public class AutomaticBrightnessController {
mPendingForegroundAppCategory = ApplicationInfo.CATEGORY_UNDEFINED;
mBrightnessRangeController = brightnessModeController;
mBrightnessThrottler = brightnessThrottler;
- mInteractiveModeBrightnessMapper = interactiveModeBrightnessMapper;
- mIdleModeBrightnessMapper = idleModeBrightnessMapper;
- // Initialize to active (normal) screen brightness mode
- switchToInteractiveScreenBrightnessMode();
+ mBrightnessMappingStrategyMap = brightnessMappingStrategyMap;
// Use the given short-term model
- setScreenBrightnessByUser(userLux, userBrightness);
+ if (userNits != BrightnessMappingStrategy.INVALID_NITS) {
+ setScreenBrightnessByUser(userLux, getBrightnessFromNits(userNits));
+ }
}
/**
@@ -358,11 +371,8 @@ public class AutomaticBrightnessController {
if (mLoggingEnabled == loggingEnabled) {
return false;
}
- if (mInteractiveModeBrightnessMapper != null) {
- mInteractiveModeBrightnessMapper.setLoggingEnabled(loggingEnabled);
- }
- if (mIdleModeBrightnessMapper != null) {
- mIdleModeBrightnessMapper.setLoggingEnabled(loggingEnabled);
+ for (int i = 0; i < mBrightnessMappingStrategyMap.size(); i++) {
+ mBrightnessMappingStrategyMap.valueAt(i).setLoggingEnabled(loggingEnabled);
}
mLoggingEnabled = loggingEnabled;
return true;
@@ -389,8 +399,7 @@ public class AutomaticBrightnessController {
| (!mAmbientLuxValid ? BrightnessEvent.FLAG_INVALID_LUX : 0)
| (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE
? BrightnessEvent.FLAG_DOZE_SCALE : 0)
- | (mCurrentBrightnessMapper.isForIdleMode()
- ? BrightnessEvent.FLAG_IDLE_CURVE : 0));
+ | (isInIdleMode() ? BrightnessEvent.FLAG_IDLE_CURVE : 0));
}
if (!mAmbientLuxValid) {
@@ -464,15 +473,13 @@ public class AutomaticBrightnessController {
// Used internally to establish whether we have deviated from the default config.
public boolean isDefaultConfig() {
- if (isInIdleMode()) {
- return false;
- }
- return mInteractiveModeBrightnessMapper.isDefaultConfig();
+ return mCurrentBrightnessMapper.getMode() == AUTO_BRIGHTNESS_MODE_DEFAULT
+ && mCurrentBrightnessMapper.isDefaultConfig();
}
// Called from APIs to get the configuration.
public BrightnessConfiguration getDefaultConfig() {
- return mInteractiveModeBrightnessMapper.getDefaultConfig();
+ return mBrightnessMappingStrategyMap.get(AUTO_BRIGHTNESS_MODE_DEFAULT).getDefaultConfig();
}
/**
@@ -527,8 +534,7 @@ public class AutomaticBrightnessController {
}
private boolean setScreenBrightnessByUser(float lux, float brightness) {
- if (lux == BrightnessMappingStrategy.NO_USER_LUX
- || brightness == BrightnessMappingStrategy.NO_USER_BRIGHTNESS) {
+ if (lux == BrightnessMappingStrategy.INVALID_LUX || Float.isNaN(brightness)) {
return false;
}
mCurrentBrightnessMapper.addUserDataPoint(lux, brightness);
@@ -543,7 +549,8 @@ public class AutomaticBrightnessController {
public boolean setBrightnessConfiguration(BrightnessConfiguration configuration,
boolean shouldResetShortTermModel) {
- if (mInteractiveModeBrightnessMapper.setBrightnessConfiguration(configuration)) {
+ if (mBrightnessMappingStrategyMap.get(AUTO_BRIGHTNESS_MODE_DEFAULT)
+ .setBrightnessConfiguration(configuration)) {
if (!isInIdleMode() && shouldResetShortTermModel) {
resetShortTermModel();
}
@@ -553,7 +560,7 @@ public class AutomaticBrightnessController {
}
public boolean isInIdleMode() {
- return mCurrentBrightnessMapper.isForIdleMode();
+ return mCurrentBrightnessMapper.getMode() == AUTO_BRIGHTNESS_MODE_IDLE;
}
public void dump(PrintWriter pw) {
@@ -595,12 +602,6 @@ public class AutomaticBrightnessController {
pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness);
pw.println(" mDisplayPolicy=" + DisplayPowerRequest.policyToString(mDisplayPolicy));
- pw.println(" mShortTermModelTimeout(active)="
- + mInteractiveModeBrightnessMapper.getShortTermModelTimeout());
- if (mIdleModeBrightnessMapper != null) {
- pw.println(" mShortTermModelTimeout(idle)="
- + mIdleModeBrightnessMapper.getShortTermModelTimeout());
- }
pw.println(" mShortTermModel=");
mShortTermModel.dump(pw);
pw.println(" mPausedShortTermModel=");
@@ -615,15 +616,14 @@ public class AutomaticBrightnessController {
pw.println(" mPendingForegroundAppPackageName=" + mPendingForegroundAppPackageName);
pw.println(" mForegroundAppCategory=" + mForegroundAppCategory);
pw.println(" mPendingForegroundAppCategory=" + mPendingForegroundAppCategory);
- pw.println(" Idle mode active=" + mCurrentBrightnessMapper.isForIdleMode());
+ pw.println(" Current mode=" + mCurrentBrightnessMapper.getMode());
pw.println();
- pw.println(" mInteractiveMapper=");
- mInteractiveModeBrightnessMapper.dump(pw,
- mBrightnessRangeController.getNormalBrightnessMax());
- if (mIdleModeBrightnessMapper != null) {
- pw.println(" mIdleMapper=");
- mIdleModeBrightnessMapper.dump(pw, mBrightnessRangeController.getNormalBrightnessMax());
+ for (int i = 0; i < mBrightnessMappingStrategyMap.size(); i++) {
+ pw.println(" Mapper for mode " + modeToString(mBrightnessMappingStrategyMap.keyAt(i))
+ + "=");
+ mBrightnessMappingStrategyMap.valueAt(i).dump(pw,
+ mBrightnessRangeController.getNormalBrightnessMax());
}
pw.println();
@@ -1117,68 +1117,58 @@ public class AutomaticBrightnessController {
updateAutoBrightness(true /* sendUpdate */, false /* isManuallySet */);
}
- void switchToIdleMode() {
- if (mIdleModeBrightnessMapper == null) {
- return;
- }
- if (mCurrentBrightnessMapper.isForIdleMode()) {
- return;
- }
- Slog.i(TAG, "Switching to Idle Screen Brightness Mode");
+ private void switchModeAndShortTermModels(@AutomaticBrightnessMode int mode) {
// Stash short term model
ShortTermModel tempShortTermModel = new ShortTermModel();
tempShortTermModel.set(mCurrentBrightnessMapper.getUserLux(),
mCurrentBrightnessMapper.getUserBrightness(), /* valid= */ true);
-
+ mHandler.removeMessages(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL);
// Send delayed timeout
mHandler.sendEmptyMessageAtTime(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL,
mClock.uptimeMillis()
+ mCurrentBrightnessMapper.getShortTermModelTimeout());
- Slog.i(TAG, "mPreviousShortTermModel" + mPausedShortTermModel);
+ Slog.i(TAG, "mPreviousShortTermModel: " + mPausedShortTermModel);
// new brightness mapper
- mCurrentBrightnessMapper = mIdleModeBrightnessMapper;
+ mCurrentBrightnessMapper = mBrightnessMappingStrategyMap.get(mode);
// if previous stm has been invalidated, and lux has drastically changed, just use
// the new, reset stm.
// if previous stm is still valid then revalidate it
- if (mPausedShortTermModel != null && !mPausedShortTermModel.maybeReset(mAmbientLux)) {
- setScreenBrightnessByUser(mPausedShortTermModel.mAnchor,
- mPausedShortTermModel.mBrightness);
+ if (mPausedShortTermModel != null) {
+ if (!mPausedShortTermModel.maybeReset(mAmbientLux)) {
+ setScreenBrightnessByUser(mPausedShortTermModel.mAnchor,
+ mPausedShortTermModel.mBrightness);
+ }
+ mPausedShortTermModel.copyFrom(tempShortTermModel);
}
- mPausedShortTermModel.copyFrom(tempShortTermModel);
update();
}
- void switchToInteractiveScreenBrightnessMode() {
- if (!mCurrentBrightnessMapper.isForIdleMode()) {
+ void switchMode(@AutomaticBrightnessMode int mode) {
+ if (!mBrightnessMappingStrategyMap.contains(mode)) {
return;
}
- Slog.i(TAG, "Switching to Interactive Screen Brightness Mode");
- ShortTermModel tempShortTermModel = new ShortTermModel();
- tempShortTermModel.set(mCurrentBrightnessMapper.getUserLux(),
- mCurrentBrightnessMapper.getUserBrightness(), /* valid= */ true);
- mHandler.removeMessages(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL);
- // Send delayed timeout
- mHandler.sendEmptyMessageAtTime(MSG_INVALIDATE_PAUSED_SHORT_TERM_MODEL,
- mClock.uptimeMillis()
- + mCurrentBrightnessMapper.getShortTermModelTimeout());
- Slog.i(TAG, "mPreviousShortTermModel" + mPausedShortTermModel.toString());
-
- // restore interactive mapper.
- mCurrentBrightnessMapper = mInteractiveModeBrightnessMapper;
-
- // if previous stm has been invalidated, and lux has drastically changed, just use
- // the new, reset stm.
- // if previous stm is still valid then revalidate it
- if (!mPausedShortTermModel.maybeReset(mAmbientLux)) {
- setScreenBrightnessByUser(mPausedShortTermModel.mAnchor,
- mPausedShortTermModel.mBrightness);
+ if (mCurrentBrightnessMapper.getMode() == mode) {
+ return;
+ }
+ Slog.i(TAG, "Switching to mode " + mode);
+ if (mode == AUTO_BRIGHTNESS_MODE_IDLE
+ || mCurrentBrightnessMapper.getMode() == AUTO_BRIGHTNESS_MODE_IDLE) {
+ switchModeAndShortTermModels(mode);
+ } else {
+ resetShortTermModel();
+ mCurrentBrightnessMapper = mBrightnessMappingStrategyMap.get(mode);
}
- mPausedShortTermModel.copyFrom(tempShortTermModel);
+ }
- update();
+ float getUserLux() {
+ return mCurrentBrightnessMapper.getUserLux();
+ }
+
+ float getUserNits() {
+ return convertToNits(mCurrentBrightnessMapper.getUserBrightness());
}
/**
@@ -1187,14 +1177,11 @@ public class AutomaticBrightnessController {
* passing the brightness value to follower displays.
*
* @param brightness The float scale value
- * @return The nit value or -1f if no conversion is possible.
+ * @return The nit value or {@link BrightnessMappingStrategy.INVALID_NITS} if no conversion is
+ * possible.
*/
public float convertToNits(float brightness) {
- if (mCurrentBrightnessMapper != null) {
- return mCurrentBrightnessMapper.convertToNits(brightness);
- } else {
- return -1.0f;
- }
+ return mCurrentBrightnessMapper.convertToNits(brightness);
}
/**
@@ -1203,14 +1190,11 @@ public class AutomaticBrightnessController {
* {@link com.android.server.display.BrightnessTracker}.
*
* @param brightness The float scale value
- * @return The nit value or -1f if no conversion is possible.
+ * @return The nit value or {@link BrightnessMappingStrategy.INVALID_NITS} if no conversion is
+ * possible.
*/
public float convertToAdjustedNits(float brightness) {
- if (mCurrentBrightnessMapper != null) {
- return mCurrentBrightnessMapper.convertToAdjustedNits(brightness);
- } else {
- return -1.0f;
- }
+ return mCurrentBrightnessMapper.convertToAdjustedNits(brightness);
}
/**
@@ -1221,12 +1205,8 @@ public class AutomaticBrightnessController {
* @return The float scale value or {@link PowerManager.BRIGHTNESS_INVALID_FLOAT} if no
* conversion is possible.
*/
- public float convertToFloatScale(float nits) {
- if (mCurrentBrightnessMapper != null) {
- return mCurrentBrightnessMapper.convertToFloatScale(nits);
- } else {
- return PowerManager.BRIGHTNESS_INVALID_FLOAT;
- }
+ public float getBrightnessFromNits(float nits) {
+ return mCurrentBrightnessMapper.getBrightnessFromNits(nits);
}
public void recalculateSplines(boolean applyAdjustment, float[] adjustment) {
@@ -1244,19 +1224,27 @@ public class AutomaticBrightnessController {
}
}
+ private String modeToString(@AutomaticBrightnessMode int mode) {
+ return switch (mode) {
+ case AUTO_BRIGHTNESS_MODE_DEFAULT -> "default";
+ case AUTO_BRIGHTNESS_MODE_IDLE -> "idle";
+ default -> Integer.toString(mode);
+ };
+ }
+
private class ShortTermModel {
// When the short term model is invalidated, we don't necessarily reset it (i.e. clear the
// user's adjustment) immediately, but wait for a drastic enough change in the ambient
// light.
// The anchor determines what were the light levels when the user has set their preference,
// and we use a relative threshold to determine when to revert to the OEM curve.
- private float mAnchor = BrightnessMappingStrategy.NO_USER_LUX;
- private float mBrightness = BrightnessMappingStrategy.NO_USER_BRIGHTNESS;
+ private float mAnchor = BrightnessMappingStrategy.INVALID_LUX;
+ private float mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private boolean mIsValid = false;
private void reset() {
- mAnchor = BrightnessMappingStrategy.NO_USER_LUX;
- mBrightness = BrightnessMappingStrategy.NO_USER_BRIGHTNESS;
+ mAnchor = BrightnessMappingStrategy.INVALID_LUX;
+ mBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mIsValid = false;
}
@@ -1279,10 +1267,8 @@ public class AutomaticBrightnessController {
private boolean maybeReset(float currentLux) {
// If the short term model was invalidated and the change is drastic enough, reset it.
// Otherwise, we revalidate it.
- if (!mIsValid && mAnchor != -1) {
- if (mCurrentBrightnessMapper != null
- && mCurrentBrightnessMapper.shouldResetShortTermModel(
- currentLux, mAnchor)) {
+ if (!mIsValid && mAnchor != BrightnessMappingStrategy.INVALID_LUX) {
+ if (mCurrentBrightnessMapper.shouldResetShortTermModel(currentLux, mAnchor)) {
resetShortTermModel();
} else {
mIsValid = true;
@@ -1304,7 +1290,7 @@ public class AutomaticBrightnessController {
}
public String toString() {
- return " mAnchor: " + mAnchor
+ return "mAnchor: " + mAnchor
+ "\n mBrightness: " + mBrightness
+ "\n mIsValid: " + mIsValid;
}
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index d848f4b6cce5..acd253b38b3d 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -18,6 +18,9 @@ package com.android.server.display;
import static android.text.TextUtils.formatSimple;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
+
import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
@@ -57,8 +60,8 @@ import java.util.Objects;
public abstract class BrightnessMappingStrategy {
private static final String TAG = "BrightnessMappingStrategy";
- public static final float NO_USER_LUX = -1;
- public static final float NO_USER_BRIGHTNESS = -1;
+ public static final float INVALID_LUX = -1;
+ public static final float INVALID_NITS = -1;
private static final float LUX_GRAD_SMOOTHING = 0.25f;
private static final float MAX_GRAD = 1.0f;
@@ -74,75 +77,48 @@ public abstract class BrightnessMappingStrategy {
private static final Plog PLOG = Plog.createSystemPlog(TAG);
/**
- * Creates a BrightnessMappingStrategy for active (normal) mode.
- * @param resources
- * @param displayDeviceConfig
- * @param displayWhiteBalanceController
- * @return the BrightnessMappingStrategy
- */
- @Nullable
- public static BrightnessMappingStrategy create(Resources resources,
- DisplayDeviceConfig displayDeviceConfig,
- DisplayWhiteBalanceController displayWhiteBalanceController) {
- return create(resources, displayDeviceConfig, /* isForIdleMode= */ false,
- displayWhiteBalanceController);
- }
-
- /**
- * Creates a BrightnessMappingStrategy for idle screen brightness mode.
- * @param resources
- * @param displayDeviceConfig
- * @param displayWhiteBalanceController
- * @return the BrightnessMappingStrategy
- */
- @Nullable
- public static BrightnessMappingStrategy createForIdleMode(Resources resources,
- DisplayDeviceConfig displayDeviceConfig, DisplayWhiteBalanceController
- displayWhiteBalanceController) {
- return create(resources, displayDeviceConfig, /* isForIdleMode= */ true,
- displayWhiteBalanceController);
- }
-
- /**
- * Creates a BrightnessMapping strategy for either active or idle screen brightness mode.
- * We do not create a simple mapping strategy for idle mode.
+ * Creates a BrightnessMapping strategy. We do not create a simple mapping strategy for idle
+ * mode.
*
* @param resources
* @param displayDeviceConfig
- * @param isForIdleMode determines whether the configurations loaded are for idle screen
- * brightness mode or active screen brightness mode.
+ * @param mode The auto-brightness mode. Different modes use different brightness curves
* @param displayWhiteBalanceController
* @return the BrightnessMappingStrategy
*/
@Nullable
- private static BrightnessMappingStrategy create(Resources resources,
- DisplayDeviceConfig displayDeviceConfig, boolean isForIdleMode,
+ static BrightnessMappingStrategy create(Resources resources,
+ DisplayDeviceConfig displayDeviceConfig,
+ @AutomaticBrightnessController.AutomaticBrightnessMode int mode,
DisplayWhiteBalanceController displayWhiteBalanceController) {
// Display independent, mode dependent values
- float[] brightnessLevelsNits;
+ float[] brightnessLevelsNits = null;
float[] brightnessLevels = null;
- float[] luxLevels;
- if (isForIdleMode) {
- brightnessLevelsNits = getFloatArray(resources.obtainTypedArray(
- com.android.internal.R.array.config_autoBrightnessDisplayValuesNitsIdle));
- luxLevels = getLuxLevels(resources.getIntArray(
- com.android.internal.R.array.config_autoBrightnessLevelsIdle));
- } else {
- brightnessLevelsNits = displayDeviceConfig.getAutoBrightnessBrighteningLevelsNits();
- luxLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevelsLux();
-
- brightnessLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevels();
- if (brightnessLevels == null || brightnessLevels.length == 0) {
- // Load the old configuration in the range [0, 255]. The values need to be
- // normalized to the range [0, 1].
- int[] brightnessLevelsInt = resources.getIntArray(
- com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
- brightnessLevels = new float[brightnessLevelsInt.length];
- for (int i = 0; i < brightnessLevels.length; i++) {
- brightnessLevels[i] = normalizeAbsoluteBrightness(brightnessLevelsInt[i]);
+ float[] luxLevels = null;
+ switch (mode) {
+ case AUTO_BRIGHTNESS_MODE_DEFAULT:
+ brightnessLevelsNits = displayDeviceConfig.getAutoBrightnessBrighteningLevelsNits();
+ luxLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevelsLux();
+
+ brightnessLevels = displayDeviceConfig.getAutoBrightnessBrighteningLevels();
+ if (brightnessLevels == null || brightnessLevels.length == 0) {
+ // Load the old configuration in the range [0, 255]. The values need to be
+ // normalized to the range [0, 1].
+ int[] brightnessLevelsInt = resources.getIntArray(
+ com.android.internal.R.array.config_autoBrightnessLcdBacklightValues);
+ brightnessLevels = new float[brightnessLevelsInt.length];
+ for (int i = 0; i < brightnessLevels.length; i++) {
+ brightnessLevels[i] = normalizeAbsoluteBrightness(brightnessLevelsInt[i]);
+ }
}
- }
+ break;
+ case AUTO_BRIGHTNESS_MODE_IDLE:
+ brightnessLevelsNits = getFloatArray(resources.obtainTypedArray(
+ com.android.internal.R.array.config_autoBrightnessDisplayValuesNitsIdle));
+ luxLevels = getLuxLevels(resources.getIntArray(
+ com.android.internal.R.array.config_autoBrightnessLevelsIdle));
+ break;
}
// Display independent, mode independent values
@@ -158,17 +134,16 @@ public abstract class BrightnessMappingStrategy {
if (isValidMapping(nitsRange, brightnessRange)
&& isValidMapping(luxLevels, brightnessLevelsNits)) {
-
BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
luxLevels, brightnessLevelsNits);
builder.setShortTermModelTimeoutMillis(shortTermModelTimeout);
builder.setShortTermModelLowerLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
builder.setShortTermModelUpperLuxMultiplier(SHORT_TERM_MODEL_THRESHOLD_RATIO);
return new PhysicalMappingStrategy(builder.build(), nitsRange, brightnessRange,
- autoBrightnessAdjustmentMaxGamma, isForIdleMode, displayWhiteBalanceController);
+ autoBrightnessAdjustmentMaxGamma, mode, displayWhiteBalanceController);
} else if (isValidMapping(luxLevels, brightnessLevels)) {
return new SimpleMappingStrategy(luxLevels, brightnessLevels,
- autoBrightnessAdjustmentMaxGamma, shortTermModelTimeout);
+ autoBrightnessAdjustmentMaxGamma, shortTermModelTimeout, mode);
} else {
return null;
}
@@ -334,7 +309,7 @@ public abstract class BrightnessMappingStrategy {
/**
* Converts the provided brightness value to nits if possible.
*
- * Returns -1.0f if there's no available mapping for the brightness to nits.
+ * Returns {@link INVALID_NITS} if there's no available mapping for the brightness to nits.
*/
public abstract float convertToNits(float brightness);
@@ -342,7 +317,7 @@ public abstract class BrightnessMappingStrategy {
* Converts the provided brightness value to nits if possible. Adjustments, such as RBC are
* applied.
*
- * Returns -1.0f if there's no available mapping for the brightness to nits.
+ * Returns {@link INVALID_NITS} if there's no available mapping for the brightness to nits.
*/
public abstract float convertToAdjustedNits(float brightness);
@@ -352,7 +327,7 @@ public abstract class BrightnessMappingStrategy {
* Returns {@link PowerManager.BRIGHTNESS_INVALID_FLOAT} if there's no available mapping for
* the nits to float scale.
*/
- public abstract float convertToFloatScale(float nits);
+ public abstract float getBrightnessFromNits(float nits);
/**
* Adds a user interaction data point to the brightness mapping.
@@ -407,17 +382,18 @@ public abstract class BrightnessMappingStrategy {
*/
public abstract void dump(PrintWriter pw, float hbmTransition);
- /**
- * We can designate a mapping strategy to be used for idle screen brightness mode.
- * @return whether this mapping strategy is to be used for idle screen brightness mode.
- */
- public abstract boolean isForIdleMode();
-
abstract float getUserLux();
abstract float getUserBrightness();
/**
+ * @return The auto-brightness mode of this mapping strategy. Different modes use different
+ * brightness curves.
+ */
+ @AutomaticBrightnessController.AutomaticBrightnessMode
+ abstract int getMode();
+
+ /**
* Check if the short term model should be reset given the anchor lux the last
* brightness change was made at and the current ambient lux.
*/
@@ -596,7 +572,7 @@ public abstract class BrightnessMappingStrategy {
if (mLoggingEnabled) {
PLOG.logCurve("gamma adjusted curve", newLux, newBrightness);
}
- if (userLux != -1) {
+ if (userLux != INVALID_LUX) {
Pair<float[], float[]> curve = insertControlPoint(newLux, newBrightness, userLux,
userBrightness);
newLux = curve.first;
@@ -624,6 +600,9 @@ public abstract class BrightnessMappingStrategy {
// Brightness control points normalized to [0, 1]
private final float[] mBrightness;
+ @AutomaticBrightnessController.AutomaticBrightnessMode
+ private final int mMode;
+
private Spline mSpline;
private float mMaxGamma;
private float mAutoBrightnessAdjustment;
@@ -632,7 +611,7 @@ public abstract class BrightnessMappingStrategy {
private long mShortTermModelTimeout;
private SimpleMappingStrategy(float[] lux, float[] brightness, float maxGamma,
- long timeout) {
+ long timeout, @AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
Preconditions.checkArgument(lux.length != 0 && brightness.length != 0,
"Lux and brightness arrays must not be empty!");
Preconditions.checkArgument(lux.length == brightness.length,
@@ -651,13 +630,14 @@ public abstract class BrightnessMappingStrategy {
mMaxGamma = maxGamma;
mAutoBrightnessAdjustment = 0;
- mUserLux = NO_USER_LUX;
- mUserBrightness = NO_USER_BRIGHTNESS;
+ mUserLux = INVALID_LUX;
+ mUserBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
if (mLoggingEnabled) {
PLOG.start("simple mapping strategy");
}
computeSpline();
mShortTermModelTimeout = timeout;
+ mMode = mode;
}
@Override
@@ -704,16 +684,16 @@ public abstract class BrightnessMappingStrategy {
@Override
public float convertToNits(float brightness) {
- return -1.0f;
+ return INVALID_NITS;
}
@Override
public float convertToAdjustedNits(float brightness) {
- return -1.0f;
+ return INVALID_NITS;
}
@Override
- public float convertToFloatScale(float nits) {
+ public float getBrightnessFromNits(float nits) {
return PowerManager.BRIGHTNESS_INVALID_FLOAT;
}
@@ -741,22 +721,22 @@ public abstract class BrightnessMappingStrategy {
@Override
public void clearUserDataPoints() {
- if (mUserLux != -1) {
+ if (mUserLux != INVALID_LUX) {
if (mLoggingEnabled) {
Slog.d(TAG, "clearUserDataPoints: " + mAutoBrightnessAdjustment + " => 0");
PLOG.start("clear user data points")
.logPoint("user data point", mUserLux, mUserBrightness);
}
mAutoBrightnessAdjustment = 0;
- mUserLux = -1;
- mUserBrightness = -1;
+ mUserLux = INVALID_LUX;
+ mUserBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
computeSpline();
}
}
@Override
public boolean hasUserDataPoints() {
- return mUserLux != -1;
+ return mUserLux != INVALID_LUX;
}
@Override
@@ -782,11 +762,12 @@ public abstract class BrightnessMappingStrategy {
pw.println(" mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
pw.println(" mUserLux=" + mUserLux);
pw.println(" mUserBrightness=" + mUserBrightness);
+ pw.println(" mShortTermModelTimeout=" + mShortTermModelTimeout);
}
@Override
- public boolean isForIdleMode() {
- return false;
+ int getMode() {
+ return mMode;
}
@Override
@@ -854,9 +835,11 @@ public abstract class BrightnessMappingStrategy {
private float mAutoBrightnessAdjustment;
private float mUserLux;
private float mUserBrightness;
- private final boolean mIsForIdleMode;
private final DisplayWhiteBalanceController mDisplayWhiteBalanceController;
+ @AutomaticBrightnessController.AutomaticBrightnessMode
+ private final int mMode;
+
// Previous short-term models and the times that they were computed stored for debugging
// purposes
private List<Spline> mPreviousBrightnessSplines = new ArrayList<>();
@@ -865,7 +848,8 @@ public abstract class BrightnessMappingStrategy {
private static final SimpleDateFormat FORMAT = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
public PhysicalMappingStrategy(BrightnessConfiguration config, float[] nits,
- float[] brightness, float maxGamma, boolean isForIdleMode,
+ float[] brightness, float maxGamma,
+ @AutomaticBrightnessController.AutomaticBrightnessMode int mode,
DisplayWhiteBalanceController displayWhiteBalanceController) {
Preconditions.checkArgument(nits.length != 0 && brightness.length != 0,
@@ -878,11 +862,11 @@ public abstract class BrightnessMappingStrategy {
Preconditions.checkArrayElementsInRange(brightness,
PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, "brightness");
- mIsForIdleMode = isForIdleMode;
+ mMode = mode;
mMaxGamma = maxGamma;
mAutoBrightnessAdjustment = 0;
- mUserLux = NO_USER_LUX;
- mUserBrightness = NO_USER_BRIGHTNESS;
+ mUserLux = INVALID_LUX;
+ mUserBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mDisplayWhiteBalanceController = displayWhiteBalanceController;
mNits = nits;
@@ -982,7 +966,7 @@ public abstract class BrightnessMappingStrategy {
}
@Override
- public float convertToFloatScale(float nits) {
+ public float getBrightnessFromNits(float nits) {
return mNitsToBrightnessSpline.interpolate(nits);
}
@@ -1024,15 +1008,15 @@ public abstract class BrightnessMappingStrategy {
.logPoint("user data point", mUserLux, mUserBrightness);
}
mAutoBrightnessAdjustment = 0;
- mUserLux = -1;
- mUserBrightness = -1;
+ mUserLux = INVALID_LUX;
+ mUserBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
computeSpline();
}
}
@Override
public boolean hasUserDataPoints() {
- return mUserLux != -1;
+ return mUserLux != INVALID_LUX;
}
@Override
@@ -1072,6 +1056,7 @@ public abstract class BrightnessMappingStrategy {
pw.println(" mUserBrightness=" + mUserBrightness);
pw.println(" mDefaultConfig=" + mDefaultConfig);
pw.println(" mBrightnessRangeAdjustmentApplied=" + mBrightnessRangeAdjustmentApplied);
+ pw.println(" shortTermModelTimeout=" + getShortTermModelTimeout());
pw.println(" Previous short-term models (oldest to newest): ");
for (int i = 0; i < mPreviousBrightnessSplines.size(); i++) {
@@ -1086,8 +1071,8 @@ public abstract class BrightnessMappingStrategy {
}
@Override
- public boolean isForIdleMode() {
- return mIsForIdleMode;
+ int getMode() {
+ return mMode;
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 2ab15e639d68..e38d08ff2a1a 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2880,7 +2880,9 @@ public final class DisplayManagerService extends SystemService {
final DisplayPowerControllerInterface displayPowerController =
mDisplayPowerControllers.get(displayId);
if (displayPowerController != null) {
- displayPowerController.setAutomaticScreenBrightnessMode(enabled);
+ displayPowerController.setAutomaticScreenBrightnessMode(enabled
+ ? AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE
+ : AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT);
}
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 2cca72e4c883..2685efecd6a1 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -16,6 +16,9 @@
package com.android.server.display;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
+
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.annotation.NonNull;
@@ -53,7 +56,6 @@ import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.FloatProperty;
-import android.util.Log;
import android.util.MathUtils;
import android.util.MutableFloat;
import android.util.MutableInt;
@@ -498,15 +500,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private Sensor mLightSensor;
private Sensor mScreenOffBrightnessSensor;
- // The mappers between ambient lux, display backlight values, and display brightness.
- // We will switch between the idle mapper and active mapper in AutomaticBrightnessController.
- // Mapper used for active (normal) screen brightness mode
- @Nullable
- private BrightnessMappingStrategy mInteractiveModeBrightnessMapper;
- // Mapper used for idle screen brightness mode
- @Nullable
- private BrightnessMappingStrategy mIdleModeBrightnessMapper;
-
// The current brightness configuration.
@Nullable
private BrightnessConfiguration mBrightnessConfiguration;
@@ -609,7 +602,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting,
Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata,
boolean bootCompleted, DisplayManagerFlags flags) {
-
+ mFlags = flags;
mInjector = injector != null ? injector : new Injector();
mClock = mInjector.getClock();
mLogicalDisplay = logicalDisplay;
@@ -767,8 +760,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mBootCompleted = bootCompleted;
-
- mFlags = flags;
}
private void applyReduceBrightColorsSplineAdjustment() {
@@ -780,13 +771,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (mAutomaticBrightnessController == null) {
return;
}
- if ((!mAutomaticBrightnessController.isInIdleMode()
- && mInteractiveModeBrightnessMapper == null)
- || (mAutomaticBrightnessController.isInIdleMode()
- && mIdleModeBrightnessMapper == null)) {
- Log.w(mTag, "No brightness mapping available to recalculate splines for this mode");
- return;
- }
float[] adjustedNits = new float[mNitsRange.length];
for (int i = 0; i < mNitsRange.length; i++) {
@@ -848,10 +832,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux,
boolean slowChange) {
mBrightnessRangeController.onAmbientLuxChange(ambientLux);
- if (nits < 0) {
+ if (nits == BrightnessMappingStrategy.INVALID_NITS) {
mBrightnessToFollow = leadDisplayBrightness;
} else {
- float brightness = convertToFloatScale(nits);
+ float brightness = getBrightnessFromNits(nits);
if (isValidBrightnessValue(brightness)) {
mBrightnessToFollow = brightness;
} else {
@@ -876,7 +860,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
synchronized (mLock) {
mDisplayBrightnessFollowers.remove(follower.getDisplayId());
mHandler.postAtTime(() -> follower.setBrightnessToFollow(
- PowerManager.BRIGHTNESS_INVALID_FLOAT, /* nits= */ -1,
+ PowerManager.BRIGHTNESS_INVALID_FLOAT, BrightnessMappingStrategy.INVALID_NITS,
/* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis());
}
}
@@ -886,7 +870,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
for (int i = 0; i < mDisplayBrightnessFollowers.size(); i++) {
DisplayPowerControllerInterface follower = mDisplayBrightnessFollowers.valueAt(i);
mHandler.postAtTime(() -> follower.setBrightnessToFollow(
- PowerManager.BRIGHTNESS_INVALID_FLOAT, /* nits= */ -1,
+ PowerManager.BRIGHTNESS_INVALID_FLOAT, BrightnessMappingStrategy.INVALID_NITS,
/* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis());
}
mDisplayBrightnessFollowers.clear();
@@ -1168,24 +1152,35 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
return;
}
- float userLux = BrightnessMappingStrategy.NO_USER_LUX;
- float userNits = -1;
- if (mInteractiveModeBrightnessMapper != null) {
- userLux = mInteractiveModeBrightnessMapper.getUserLux();
- float userBrightness = mInteractiveModeBrightnessMapper.getUserBrightness();
- userNits = mInteractiveModeBrightnessMapper.convertToNits(userBrightness);
- }
+ SparseArray<BrightnessMappingStrategy> brightnessMappers = new SparseArray<>();
+
+ BrightnessMappingStrategy defaultModeBrightnessMapper =
+ mInjector.getDefaultModeBrightnessMapper(resources, mDisplayDeviceConfig,
+ mDisplayWhiteBalanceController);
+ brightnessMappers.append(AUTO_BRIGHTNESS_MODE_DEFAULT,
+ defaultModeBrightnessMapper);
final boolean isIdleScreenBrightnessEnabled = resources.getBoolean(
R.bool.config_enableIdleScreenBrightnessMode);
- mInteractiveModeBrightnessMapper = mInjector.getInteractiveModeBrightnessMapper(resources,
- mDisplayDeviceConfig, mDisplayWhiteBalanceController);
if (isIdleScreenBrightnessEnabled) {
- mIdleModeBrightnessMapper = BrightnessMappingStrategy.createForIdleMode(resources,
- mDisplayDeviceConfig, mDisplayWhiteBalanceController);
+ BrightnessMappingStrategy idleModeBrightnessMapper =
+ BrightnessMappingStrategy.create(resources, mDisplayDeviceConfig,
+ AUTO_BRIGHTNESS_MODE_IDLE,
+ mDisplayWhiteBalanceController);
+ if (idleModeBrightnessMapper != null) {
+ brightnessMappers.append(AUTO_BRIGHTNESS_MODE_IDLE,
+ idleModeBrightnessMapper);
+ }
+ }
+
+ float userLux = BrightnessMappingStrategy.INVALID_LUX;
+ float userNits = BrightnessMappingStrategy.INVALID_NITS;
+ if (mAutomaticBrightnessController != null) {
+ userLux = mAutomaticBrightnessController.getUserLux();
+ userNits = mAutomaticBrightnessController.getUserNits();
}
- if (mInteractiveModeBrightnessMapper != null) {
+ if (defaultModeBrightnessMapper != null) {
final float dozeScaleFactor = resources.getFraction(
com.android.internal.R.fraction.config_screenAutoBrightnessDozeScaleFactor,
1, 1);
@@ -1297,25 +1292,17 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.stop();
}
- float userBrightness = BrightnessMappingStrategy.NO_USER_BRIGHTNESS;
- if (userNits >= 0) {
- userBrightness = mInteractiveModeBrightnessMapper.convertToFloatScale(userNits);
- if (Float.isNaN(userBrightness)) {
- userBrightness = BrightnessMappingStrategy.NO_USER_BRIGHTNESS;
- }
- }
mAutomaticBrightnessController = mInjector.getAutomaticBrightnessController(
this, handler.getLooper(), mSensorManager, mLightSensor,
- mInteractiveModeBrightnessMapper, lightSensorWarmUpTimeConfig,
- PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, dozeScaleFactor,
- lightSensorRate, initialLightSensorRate, brighteningLightDebounce,
- darkeningLightDebounce, brighteningLightDebounceIdle,
- darkeningLightDebounceIdle, autoBrightnessResetAmbientLuxAfterWarmUp,
- ambientBrightnessThresholds, screenBrightnessThresholds,
- ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, mContext,
- mBrightnessRangeController, mBrightnessThrottler, mIdleModeBrightnessMapper,
- mDisplayDeviceConfig.getAmbientHorizonShort(),
- mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userBrightness);
+ brightnessMappers, lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN,
+ PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate,
+ initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
+ brighteningLightDebounceIdle, darkeningLightDebounceIdle,
+ autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
+ screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
+ screenBrightnessThresholdsIdle, mContext, mBrightnessRangeController,
+ mBrightnessThrottler, mDisplayDeviceConfig.getAmbientHorizonShort(),
+ mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userNits);
mBrightnessEventRingBuffer =
new RingBuffer<>(BrightnessEvent.class, RINGBUFFER_MAX);
@@ -1334,7 +1321,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
mHandler,
SystemClock::uptimeMillis,
sensorValueToLux,
- mInteractiveModeBrightnessMapper);
+ defaultModeBrightnessMapper);
}
} else {
mUseSoftwareAutoBrightnessConfig = false;
@@ -1377,13 +1364,11 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
}
@Override
- public void setAutomaticScreenBrightnessMode(boolean isIdle) {
+ public void setAutomaticScreenBrightnessMode(
+ @AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
+ boolean isIdle = mode == AUTO_BRIGHTNESS_MODE_IDLE;
if (mAutomaticBrightnessController != null) {
- if (isIdle) {
- mAutomaticBrightnessController.switchToIdleMode();
- } else {
- mAutomaticBrightnessController.switchToInteractiveScreenBrightnessMode();
- }
+ mAutomaticBrightnessController.switchMode(mode);
setAnimatorRampSpeeds(isIdle);
}
@@ -2810,7 +2795,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
float brightnessNitsForDefaultDisplay =
mBrightnessSetting.getBrightnessNitsForDefaultDisplay();
if (brightnessNitsForDefaultDisplay >= 0) {
- float brightnessForDefaultDisplay = convertToFloatScale(
+ float brightnessForDefaultDisplay = getBrightnessFromNits(
brightnessNitsForDefaultDisplay);
if (isValidBrightnessValue(brightnessForDefaultDisplay)) {
mBrightnessSetting.setBrightness(brightnessForDefaultDisplay);
@@ -2944,23 +2929,23 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private float convertToNits(float brightness) {
if (mAutomaticBrightnessController == null) {
- return -1f;
+ return BrightnessMappingStrategy.INVALID_NITS;
}
return mAutomaticBrightnessController.convertToNits(brightness);
}
private float convertToAdjustedNits(float brightness) {
if (mAutomaticBrightnessController == null) {
- return -1f;
+ return BrightnessMappingStrategy.INVALID_NITS;
}
return mAutomaticBrightnessController.convertToAdjustedNits(brightness);
}
- private float convertToFloatScale(float nits) {
+ private float getBrightnessFromNits(float nits) {
if (mAutomaticBrightnessController == null) {
return PowerManager.BRIGHTNESS_INVALID_FLOAT;
}
- return mAutomaticBrightnessController.convertToFloatScale(nits);
+ return mAutomaticBrightnessController.getBrightnessFromNits(nits);
}
@GuardedBy("mLock")
@@ -3635,7 +3620,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
AutomaticBrightnessController getAutomaticBrightnessController(
AutomaticBrightnessController.Callbacks callbacks, Looper looper,
SensorManager sensorManager, Sensor lightSensor,
- BrightnessMappingStrategy interactiveModeBrightnessMapper,
+ SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap,
int lightSensorWarmUpTime, float brightnessMin, float brightnessMax,
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
@@ -3645,27 +3630,27 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
HysteresisLevels screenBrightnessThresholds,
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
- BrightnessRangeController brightnessRangeController,
- BrightnessThrottler brightnessThrottler,
- BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
- int ambientLightHorizonLong, float userLux, float userBrightness) {
+ BrightnessRangeController brightnessModeController,
+ BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
+ int ambientLightHorizonLong, float userLux, float userNits) {
return new AutomaticBrightnessController(callbacks, looper, sensorManager, lightSensor,
- interactiveModeBrightnessMapper, lightSensorWarmUpTime, brightnessMin,
+ brightnessMappingStrategyMap, lightSensorWarmUpTime, brightnessMin,
brightnessMax, dozeScaleFactor, lightSensorRate, initialLightSensorRate,
brighteningLightDebounceConfig, darkeningLightDebounceConfig,
brighteningLightDebounceConfigIdle, darkeningLightDebounceConfigIdle,
resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds,
screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
- screenBrightnessThresholdsIdle, context, brightnessRangeController,
- brightnessThrottler, idleModeBrightnessMapper, ambientLightHorizonShort,
- ambientLightHorizonLong, userLux, userBrightness);
+ screenBrightnessThresholdsIdle, context, brightnessModeController,
+ brightnessThrottler, ambientLightHorizonShort, ambientLightHorizonLong, userLux,
+ userNits);
}
- BrightnessMappingStrategy getInteractiveModeBrightnessMapper(Resources resources,
+ BrightnessMappingStrategy getDefaultModeBrightnessMapper(Resources resources,
DisplayDeviceConfig displayDeviceConfig,
DisplayWhiteBalanceController displayWhiteBalanceController) {
return BrightnessMappingStrategy.create(resources,
- displayDeviceConfig, displayWhiteBalanceController);
+ displayDeviceConfig, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ displayWhiteBalanceController);
}
HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages,
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 810ac08e32c1..52c53f3d658e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -16,6 +16,9 @@
package com.android.server.display;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
+
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.annotation.Nullable;
@@ -52,7 +55,6 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.FloatProperty;
import android.util.IndentingPrintWriter;
-import android.util.Log;
import android.util.MathUtils;
import android.util.MutableFloat;
import android.util.MutableInt;
@@ -442,15 +444,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
private Sensor mLightSensor;
private Sensor mScreenOffBrightnessSensor;
- // The mappers between ambient lux, display backlight values, and display brightness.
- // We will switch between the idle mapper and active mapper in AutomaticBrightnessController.
- // Mapper used for active (normal) screen brightness mode
- @Nullable
- private BrightnessMappingStrategy mInteractiveModeBrightnessMapper;
- // Mapper used for idle screen brightness mode
- @Nullable
- private BrightnessMappingStrategy mIdleModeBrightnessMapper;
-
private boolean mIsRbcActive;
// Animators.
@@ -490,7 +483,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
BrightnessTracker brightnessTracker, BrightnessSetting brightnessSetting,
Runnable onBrightnessChangeRunnable, HighBrightnessModeMetadata hbmMetadata,
boolean bootCompleted, DisplayManagerFlags flags) {
-
+ mFlags = flags;
mInjector = injector != null ? injector : new Injector();
mClock = mInjector.getClock();
mLogicalDisplay = logicalDisplay;
@@ -636,7 +629,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
R.bool.config_displayBrightnessBucketsInDoze);
mBootCompleted = bootCompleted;
- mFlags = flags;
}
private void applyReduceBrightColorsSplineAdjustment() {
@@ -648,13 +640,6 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
if (mAutomaticBrightnessController == null) {
return;
}
- if ((!mAutomaticBrightnessController.isInIdleMode()
- && mInteractiveModeBrightnessMapper == null)
- || (mAutomaticBrightnessController.isInIdleMode()
- && mIdleModeBrightnessMapper == null)) {
- Log.w(mTag, "No brightness mapping available to recalculate splines for this mode");
- return;
- }
float[] adjustedNits = new float[mNitsRange.length];
for (int i = 0; i < mNitsRange.length; i++) {
@@ -987,24 +972,35 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
return;
}
- float userLux = BrightnessMappingStrategy.NO_USER_LUX;
- float userNits = -1;
- if (mInteractiveModeBrightnessMapper != null) {
- userLux = mInteractiveModeBrightnessMapper.getUserLux();
- float userBrightness = mInteractiveModeBrightnessMapper.getUserBrightness();
- userNits = mInteractiveModeBrightnessMapper.convertToNits(userBrightness);
- }
+ SparseArray<BrightnessMappingStrategy> brightnessMappers = new SparseArray<>();
+
+ BrightnessMappingStrategy defaultModeBrightnessMapper =
+ mInjector.getDefaultModeBrightnessMapper(resources, mDisplayDeviceConfig,
+ mDisplayWhiteBalanceController);
+ brightnessMappers.append(AUTO_BRIGHTNESS_MODE_DEFAULT,
+ defaultModeBrightnessMapper);
final boolean isIdleScreenBrightnessEnabled = resources.getBoolean(
R.bool.config_enableIdleScreenBrightnessMode);
- mInteractiveModeBrightnessMapper = mInjector.getInteractiveModeBrightnessMapper(resources,
- mDisplayDeviceConfig, mDisplayWhiteBalanceController);
if (isIdleScreenBrightnessEnabled) {
- mIdleModeBrightnessMapper = BrightnessMappingStrategy.createForIdleMode(resources,
- mDisplayDeviceConfig, mDisplayWhiteBalanceController);
+ BrightnessMappingStrategy idleModeBrightnessMapper =
+ BrightnessMappingStrategy.create(resources, mDisplayDeviceConfig,
+ AUTO_BRIGHTNESS_MODE_IDLE,
+ mDisplayWhiteBalanceController);
+ if (idleModeBrightnessMapper != null) {
+ brightnessMappers.append(AUTO_BRIGHTNESS_MODE_IDLE,
+ idleModeBrightnessMapper);
+ }
+ }
+
+ float userLux = BrightnessMappingStrategy.INVALID_LUX;
+ float userNits = BrightnessMappingStrategy.INVALID_NITS;
+ if (mAutomaticBrightnessController != null) {
+ userLux = mAutomaticBrightnessController.getUserLux();
+ userNits = mAutomaticBrightnessController.getUserNits();
}
- if (mInteractiveModeBrightnessMapper != null) {
+ if (defaultModeBrightnessMapper != null) {
final float dozeScaleFactor = resources.getFraction(
R.fraction.config_screenAutoBrightnessDozeScaleFactor,
1, 1);
@@ -1116,25 +1112,17 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.stop();
}
- float userBrightness = BrightnessMappingStrategy.NO_USER_BRIGHTNESS;
- if (userNits >= 0) {
- userBrightness = mInteractiveModeBrightnessMapper.convertToFloatScale(userNits);
- if (Float.isNaN(userBrightness)) {
- userBrightness = BrightnessMappingStrategy.NO_USER_BRIGHTNESS;
- }
- }
mAutomaticBrightnessController = mInjector.getAutomaticBrightnessController(
this, handler.getLooper(), mSensorManager, mLightSensor,
- mInteractiveModeBrightnessMapper, lightSensorWarmUpTimeConfig,
- PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, dozeScaleFactor,
- lightSensorRate, initialLightSensorRate, brighteningLightDebounce,
- darkeningLightDebounce, brighteningLightDebounceIdle,
- darkeningLightDebounceIdle, autoBrightnessResetAmbientLuxAfterWarmUp,
- ambientBrightnessThresholds, screenBrightnessThresholds,
- ambientBrightnessThresholdsIdle, screenBrightnessThresholdsIdle, mContext,
- mBrightnessRangeController, mBrightnessThrottler, mIdleModeBrightnessMapper,
- mDisplayDeviceConfig.getAmbientHorizonShort(),
- mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userBrightness);
+ brightnessMappers, lightSensorWarmUpTimeConfig, PowerManager.BRIGHTNESS_MIN,
+ PowerManager.BRIGHTNESS_MAX, dozeScaleFactor, lightSensorRate,
+ initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
+ brighteningLightDebounceIdle, darkeningLightDebounceIdle,
+ autoBrightnessResetAmbientLuxAfterWarmUp, ambientBrightnessThresholds,
+ screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
+ screenBrightnessThresholdsIdle, mContext, mBrightnessRangeController,
+ mBrightnessThrottler, mDisplayDeviceConfig.getAmbientHorizonShort(),
+ mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userNits);
mDisplayBrightnessController.setAutomaticBrightnessController(
mAutomaticBrightnessController);
@@ -1157,7 +1145,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
mHandler,
SystemClock::uptimeMillis,
sensorValueToLux,
- mInteractiveModeBrightnessMapper);
+ defaultModeBrightnessMapper);
}
} else {
mUseSoftwareAutoBrightnessConfig = false;
@@ -1200,13 +1188,11 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
}
@Override
- public void setAutomaticScreenBrightnessMode(boolean isIdle) {
+ public void setAutomaticScreenBrightnessMode(
+ @AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
+ boolean isIdle = mode == AUTO_BRIGHTNESS_MODE_IDLE;
if (mAutomaticBrightnessController != null) {
- if (isIdle) {
- mAutomaticBrightnessController.switchToIdleMode();
- } else {
- mAutomaticBrightnessController.switchToInteractiveScreenBrightnessMode();
- }
+ mAutomaticBrightnessController.switchMode(mode);
setAnimatorRampSpeeds(isIdle);
}
Message msg = mHandler.obtainMessage();
@@ -2351,10 +2337,10 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
public void setBrightnessToFollow(float leadDisplayBrightness, float nits, float ambientLux,
boolean slowChange) {
mBrightnessRangeController.onAmbientLuxChange(ambientLux);
- if (nits < 0) {
+ if (nits == BrightnessMappingStrategy.INVALID_NITS) {
mDisplayBrightnessController.setBrightnessToFollow(leadDisplayBrightness, slowChange);
} else {
- float brightness = mDisplayBrightnessController.convertToFloatScale(nits);
+ float brightness = mDisplayBrightnessController.getBrightnessFromNits(nits);
if (BrightnessUtils.isValidBrightnessValue(brightness)) {
mDisplayBrightnessController.setBrightnessToFollow(brightness, slowChange);
} else {
@@ -2421,7 +2407,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
synchronized (mLock) {
mDisplayBrightnessFollowers.remove(follower.getDisplayId());
mHandler.postAtTime(() -> follower.setBrightnessToFollow(
- PowerManager.BRIGHTNESS_INVALID_FLOAT, /* nits= */ -1,
+ PowerManager.BRIGHTNESS_INVALID_FLOAT, BrightnessMappingStrategy.INVALID_NITS,
/* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis());
}
}
@@ -2431,7 +2417,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
for (int i = 0; i < mDisplayBrightnessFollowers.size(); i++) {
DisplayPowerControllerInterface follower = mDisplayBrightnessFollowers.valueAt(i);
mHandler.postAtTime(() -> follower.setBrightnessToFollow(
- PowerManager.BRIGHTNESS_INVALID_FLOAT, /* nits= */ -1,
+ PowerManager.BRIGHTNESS_INVALID_FLOAT, BrightnessMappingStrategy.INVALID_NITS,
/* ambientLux= */ 0, /* slowChange= */ false), mClock.uptimeMillis());
}
mDisplayBrightnessFollowers.clear();
@@ -3012,7 +2998,7 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
AutomaticBrightnessController getAutomaticBrightnessController(
AutomaticBrightnessController.Callbacks callbacks, Looper looper,
SensorManager sensorManager, Sensor lightSensor,
- BrightnessMappingStrategy interactiveModeBrightnessMapper,
+ SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap,
int lightSensorWarmUpTime, float brightnessMin, float brightnessMax,
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
@@ -3023,26 +3009,26 @@ final class DisplayPowerController2 implements AutomaticBrightnessController.Cal
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
BrightnessRangeController brightnessModeController,
- BrightnessThrottler brightnessThrottler,
- BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
- int ambientLightHorizonLong, float userLux, float userBrightness) {
+ BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
+ int ambientLightHorizonLong, float userLux, float userNits) {
return new AutomaticBrightnessController(callbacks, looper, sensorManager, lightSensor,
- interactiveModeBrightnessMapper, lightSensorWarmUpTime, brightnessMin,
+ brightnessMappingStrategyMap, lightSensorWarmUpTime, brightnessMin,
brightnessMax, dozeScaleFactor, lightSensorRate, initialLightSensorRate,
brighteningLightDebounceConfig, darkeningLightDebounceConfig,
brighteningLightDebounceConfigIdle, darkeningLightDebounceConfigIdle,
resetAmbientLuxAfterWarmUpConfig, ambientBrightnessThresholds,
screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
screenBrightnessThresholdsIdle, context, brightnessModeController,
- brightnessThrottler, idleModeBrightnessMapper, ambientLightHorizonShort,
- ambientLightHorizonLong, userLux, userBrightness);
+ brightnessThrottler, ambientLightHorizonShort, ambientLightHorizonLong, userLux,
+ userNits);
}
- BrightnessMappingStrategy getInteractiveModeBrightnessMapper(Resources resources,
+ BrightnessMappingStrategy getDefaultModeBrightnessMapper(Resources resources,
DisplayDeviceConfig displayDeviceConfig,
DisplayWhiteBalanceController displayWhiteBalanceController) {
return BrightnessMappingStrategy.create(resources,
- displayDeviceConfig, displayWhiteBalanceController);
+ displayDeviceConfig, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ displayWhiteBalanceController);
}
HysteresisLevels getHysteresisLevels(float[] brighteningThresholdsPercentages,
diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
index 72079a4c82fe..c27918430254 100644
--- a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
+++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
@@ -69,9 +69,10 @@ public interface DisplayPowerControllerInterface {
/**
* Used to decide the associated AutomaticBrightnessController's BrightnessMode
- * @param isIdle Flag which represents if the Idle BrightnessMode is to be set
+ * @param mode The auto-brightness mode
*/
- void setAutomaticScreenBrightnessMode(boolean isIdle);
+ void setAutomaticScreenBrightnessMode(
+ @AutomaticBrightnessController.AutomaticBrightnessMode int mode);
/**
* Used to enable/disable the logging of the WhileBalance associated entities
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
index 617befbbd17d..3bb798689ea6 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -27,6 +27,7 @@ import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.AutomaticBrightnessController;
+import com.android.server.display.BrightnessMappingStrategy;
import com.android.server.display.BrightnessSetting;
import com.android.server.display.DisplayBrightnessState;
import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
@@ -359,11 +360,12 @@ public final class DisplayBrightnessController {
* passing the brightness value to follower displays.
*
* @param brightness The float scale value
- * @return The nit value or -1f if no conversion is possible.
+ * @return The nit value or {@link BrightnessMappingStrategy.INVALID_NITS} if no conversion is
+ * possible.
*/
public float convertToNits(float brightness) {
if (mAutomaticBrightnessController == null) {
- return -1f;
+ return BrightnessMappingStrategy.INVALID_NITS;
}
return mAutomaticBrightnessController.convertToNits(brightness);
}
@@ -374,11 +376,12 @@ public final class DisplayBrightnessController {
* {@link com.android.server.display.BrightnessTracker}.
*
* @param brightness The float scale value
- * @return The nit value or -1f if no conversion is possible.
+ * @return The nit value or {@link BrightnessMappingStrategy.INVALID_NITS} if no conversion is
+ * possible.
*/
public float convertToAdjustedNits(float brightness) {
if (mAutomaticBrightnessController == null) {
- return -1f;
+ return BrightnessMappingStrategy.INVALID_NITS;
}
return mAutomaticBrightnessController.convertToAdjustedNits(brightness);
}
@@ -391,11 +394,11 @@ public final class DisplayBrightnessController {
* @return The float scale value or {@link PowerManager.BRIGHTNESS_INVALID_FLOAT} if no
* conversion is possible.
*/
- public float convertToFloatScale(float nits) {
+ public float getBrightnessFromNits(float nits) {
if (mAutomaticBrightnessController == null) {
return PowerManager.BRIGHTNESS_INVALID_FLOAT;
}
- return mAutomaticBrightnessController.convertToFloatScale(nits);
+ return mAutomaticBrightnessController.getBrightnessFromNits(nits);
}
/**
@@ -497,7 +500,7 @@ public final class DisplayBrightnessController {
float brightnessNitsForDefaultDisplay =
mBrightnessSetting.getBrightnessNitsForDefaultDisplay();
if (brightnessNitsForDefaultDisplay >= 0) {
- float brightnessForDefaultDisplay = convertToFloatScale(
+ float brightnessForDefaultDisplay = getBrightnessFromNits(
brightnessNitsForDefaultDisplay);
if (BrightnessUtils.isValidBrightnessValue(brightnessForDefaultDisplay)) {
mBrightnessSetting.setBrightness(brightnessForDefaultDisplay);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index b3aa351d69d7..70993ca3e21b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -201,7 +201,8 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
if (WAKE_ON_HOTPLUG && connected) {
mService.wakeUp();
}
- if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
+ HdmiPortInfo portInfo = mService.getPortInfo(portId);
+ if (portInfo != null && portInfo.getType() == HdmiPortInfo.PORT_OUTPUT) {
mCecMessageCache.flushAll();
if (!connected) {
if (isSystemAudioActivated()) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 7e8a2cc6d835..29303aab6fa9 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -92,7 +92,8 @@ abstract class HdmiCecLocalDeviceSource extends HdmiCecLocalDevice {
@ServiceThreadOnly
void onHotplug(int portId, boolean connected) {
assertRunOnServiceThread();
- if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
+ HdmiPortInfo portInfo = mService.getPortInfo(portId);
+ if (portInfo != null && portInfo.getType() == HdmiPortInfo.PORT_OUTPUT) {
mCecMessageCache.flushAll();
}
// We'll not invalidate the active source on the hotplug event to pass CETC 11.2.2-2 ~ 3.
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b3926fd1b5ba..92537064f766 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1783,8 +1783,9 @@ public class HdmiControlService extends SystemService {
// initPortInfo at hotplug event.
mHdmiCecNetwork.initPortInfo();
+ HdmiPortInfo portInfo = getPortInfo(portId);
if (connected && !isTvDevice()
- && getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
+ && portInfo != null && portInfo.getType() == HdmiPortInfo.PORT_OUTPUT) {
ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
for (int type : getCecLocalDeviceTypes()) {
HdmiCecLocalDevice localDevice = mHdmiCecNetwork.getLocalDevice(type);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 972f85793556..24e23003d12b 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3511,6 +3511,13 @@ public class InputManagerService extends IInputManager.Stub
mNative.setAccessibilityBounceKeysThreshold(thresholdTimeMs);
}
+ /**
+ * Sets whether Accessibility sticky keys is enabled.
+ */
+ public void setAccessibilityStickyKeysEnabled(boolean enabled) {
+ mNative.setAccessibilityStickyKeysEnabled(enabled);
+ }
+
interface KeyboardBacklightControllerInterface {
default void incrementKeyboardBacklight(int deviceId) {}
default void decrementKeyboardBacklight(int deviceId) {}
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 0012eab11277..c9668a236f48 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -87,7 +87,9 @@ class InputSettingsObserver extends ContentObserver {
Map.entry(Settings.System.getUriFor(Settings.System.SHOW_ROTARY_INPUT),
(reason) -> updateShowRotaryInput()),
Map.entry(Settings.System.getUriFor(Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS),
- (reason) -> updateAccessibilityBounceKeys()));
+ (reason) -> updateAccessibilityBounceKeys()),
+ Map.entry(Settings.System.getUriFor(Settings.Secure.ACCESSIBILITY_STICKY_KEYS),
+ (reason) -> updateAccessibilityStickyKeys()));
}
/**
@@ -223,4 +225,9 @@ class InputSettingsObserver extends ContentObserver {
mService.setAccessibilityBounceKeysThreshold(
InputSettings.getAccessibilityBounceKeysThreshold(mContext));
}
+
+ private void updateAccessibilityStickyKeys() {
+ mService.setAccessibilityStickyKeysEnabled(
+ InputSettings.isAccessibilityStickyKeysEnabled(mContext));
+ }
}
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 49bbe9a7655c..829b6607f113 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -251,6 +251,11 @@ interface NativeInputManagerService {
*/
void setAccessibilityBounceKeysThreshold(int thresholdTimeMs);
+ /**
+ * Notify if Accessibility sticky keys is enabled/disabled from InputSettings.
+ */
+ void setAccessibilityStickyKeysEnabled(boolean enabled);
+
/** The native implementation of InputManagerService methods. */
class NativeImpl implements NativeInputManagerService {
/** Pointer to native input manager service object, used by native code. */
@@ -508,5 +513,8 @@ interface NativeInputManagerService {
@Override
public native void setAccessibilityBounceKeysThreshold(int thresholdTimeMs);
+
+ @Override
+ public native void setAccessibilityStickyKeysEnabled(boolean enabled);
}
}
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index d3eb5a95ccdc..91e6a80a5bbb 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -1734,12 +1734,6 @@ public class LocationProviderManager extends
return null;
}
- // lastly - note app ops
- if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
- identity)) {
- return null;
- }
-
Location location = getPermittedLocation(
getLastLocationUnsafe(
identity.getUserId(),
@@ -1748,10 +1742,18 @@ public class LocationProviderManager extends
Long.MAX_VALUE),
permissionLevel);
- if (location != null && identity.getPid() == Process.myPid()) {
+ if (location != null) {
+ // lastly - note app ops
+ if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(permissionLevel),
+ identity)) {
+ return null;
+ }
+
// if delivering to the same process, make a copy of the location first (since
// location is mutable)
- location = new Location(location);
+ if (identity.getPid() == Process.myPid()) {
+ location = new Location(location);
+ }
}
return location;
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index da017453ed8b..55d8a0fd1fa1 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -33,4 +33,11 @@ flag {
namespace: "systemui"
description: "This flag controls the vibrate while unlocked setting of polite notifications"
bug: "270456865"
-} \ No newline at end of file
+}
+
+flag {
+ name: "autogroup_summary_icon_update"
+ namespace: "systemui"
+ description: "This flag controls the fix for notifications autogroup summary icon updates"
+ bug: "227693160"
+}
diff --git a/services/core/java/com/android/server/pm/Computer.java b/services/core/java/com/android/server/pm/Computer.java
index 482807c397ea..27f4e11c53ad 100644
--- a/services/core/java/com/android/server/pm/Computer.java
+++ b/services/core/java/com/android/server/pm/Computer.java
@@ -518,9 +518,7 @@ public interface Computer extends PackageDataSnapshot {
boolean isPackageStoppedForUser(@NonNull String packageName, @UserIdInt int userId)
throws PackageManager.NameNotFoundException;
- /** Check if the package is suspending any package. */
- boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
- @UserIdInt int suspendingUserId, int targetUserId);
+ boolean isSuspendingAnyPackages(@NonNull String suspendingPackage, @UserIdInt int userId);
@NonNull
ParceledListSlice<IntentFilter> getAllIntentFilters(@NonNull String packageName);
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index 3cb2420cd223..744c94661067 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -96,7 +96,6 @@ import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
-import android.content.pm.UserPackage;
import android.content.pm.VersionedPackage;
import android.os.Binder;
import android.os.Build;
@@ -5009,13 +5008,11 @@ public class ComputerEngine implements Computer {
@Override
public boolean isSuspendingAnyPackages(@NonNull String suspendingPackage,
- @UserIdInt int suspendingUserId, int targetUserId) {
- final UserPackage suspender = UserPackage.of(suspendingUserId, suspendingPackage);
+ @UserIdInt int userId) {
for (final PackageStateInternal packageState : getPackageStates().values()) {
- final PackageUserStateInternal state =
- packageState.getUserStateOrDefault(targetUserId);
+ final PackageUserStateInternal state = packageState.getUserStateOrDefault(userId);
if (state.getSuspendParams() != null
- && state.getSuspendParams().containsKey(suspender)) {
+ && state.getSuspendParams().containsKey(suspendingPackage)) {
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
index 8da168375447..c737b45ae885 100644
--- a/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
+++ b/services/core/java/com/android/server/pm/PackageManagerInternalBase.java
@@ -19,8 +19,6 @@ package com.android.server.pm;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
-import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -39,7 +37,6 @@ import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
-import android.content.pm.UserPackage;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -253,7 +250,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
getSuspendPackageHelper().removeSuspensionsBySuspendingPackage(snapshot(),
new String[]{packageName},
(suspendingPackage) -> !PackageManagerService.PLATFORM_PACKAGE_NAME.equals(
- suspendingPackage.packageName),
+ suspendingPackage),
userId);
}
@@ -272,7 +269,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
- public final UserPackage getSuspendingPackage(String suspendedPackage, int userId) {
+ public final String getSuspendingPackage(String suspendedPackage, int userId) {
return getSuspendPackageHelper().getSuspendingPackage(snapshot(), suspendedPackage, userId,
Binder.getCallingUid());
}
@@ -280,7 +277,7 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
public final SuspendDialogInfo getSuspendedDialogInfo(String suspendedPackage,
- UserPackage suspendingPackage, int userId) {
+ String suspendingPackage, int userId) {
return getSuspendPackageHelper().getSuspendedDialogInfo(snapshot(), suspendedPackage,
suspendingPackage, userId, Binder.getCallingUid());
}
@@ -686,16 +683,14 @@ abstract class PackageManagerInternalBase extends PackageManagerInternal {
@Override
@Deprecated
- public final void unsuspendAdminSuspendedPackages(int affectedUser) {
- final int suspendingUserId = affectedUser;
- mService.unsuspendForSuspendingPackage(snapshot(), PLATFORM_PACKAGE_NAME, suspendingUserId);
+ public final void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
+ mService.unsuspendForSuspendingPackage(snapshot(), packageName, affectedUser);
}
@Override
@Deprecated
- public final boolean isAdminSuspendingAnyPackages(int userId) {
- final int suspendingUserId = userId;
- return snapshot().isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, suspendingUserId, userId);
+ public final boolean isSuspendingAnyPackages(String suspendingPackage, int userId) {
+ return snapshot().isSuspendingAnyPackages(suspendingPackage, userId);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bc441b84c58b..56365b676618 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -292,7 +292,6 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
-import java.util.function.Predicate;
/**
* Keep track of all those APKs everywhere.
@@ -3138,7 +3137,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
}
private void enforceCanSetPackagesSuspendedAsUser(@NonNull Computer snapshot,
- boolean quarantined, UserPackage suspender, int callingUid, int targetUserId,
+ boolean quarantined, String callingPackage, int callingUid, int userId,
String callingMethod) {
if (callingUid == Process.ROOT_UID
// Need to compare app-id to allow system dialogs access on secondary users
@@ -3146,10 +3145,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
return;
}
- final String ownerPackage =
- mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(targetUserId);
+ final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
if (ownerPackage != null) {
- final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, targetUserId);
+ final int ownerUid = snapshot.getPackageUid(ownerPackage, 0, userId);
if (ownerUid == callingUid) {
return;
}
@@ -3170,27 +3168,25 @@ public class PackageManagerService implements PackageSender, TestUtilityService
callingMethod);
}
- final int packageUid = snapshot.getPackageUid(suspender.packageName, 0, targetUserId);
+ final int packageUid = snapshot.getPackageUid(callingPackage, 0, userId);
final boolean allowedPackageUid = packageUid == callingUid;
// TODO(b/139383163): remove special casing for shell and enforce INTERACT_ACROSS_USERS_FULL
final boolean allowedShell = callingUid == SHELL_UID
&& UserHandle.isSameApp(packageUid, callingUid);
if (!allowedShell && !allowedPackageUid) {
- throw new SecurityException("Suspending package " + suspender.packageName
- + " in user " + targetUserId + " does not belong to calling uid " + callingUid);
+ throw new SecurityException("Calling package " + callingPackage + " in user "
+ + userId + " does not belong to calling uid " + callingUid);
}
}
void unsuspendForSuspendingPackage(@NonNull Computer computer, String suspendingPackage,
- @UserIdInt int suspendingUserId) {
+ @UserIdInt int userId) {
// TODO: This can be replaced by a special parameter to iterate all packages, rather than
// this weird pre-collect of all packages.
final String[] allPackages = computer.getPackageStates().keySet().toArray(new String[0]);
- final Predicate<UserPackage> suspenderPredicate =
- UserPackage.of(suspendingUserId, suspendingPackage)::equals;
mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer,
- allPackages, suspenderPredicate, suspendingUserId);
+ allPackages, suspendingPackage::equals, userId);
}
void removeAllDistractingPackageRestrictions(@NonNull Computer snapshot, int userId) {
@@ -5263,9 +5259,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
if (!snapshot.isPackageSuspendedForUser(packageName, userId)) {
return null;
}
- final UserPackage suspender = mSuspendPackageHelper.getSuspendingPackage(
- snapshot, packageName, userId, callingUid);
- return suspender != null ? suspender.packageName : null;
+ return mSuspendPackageHelper.getSuspendingPackage(snapshot, packageName, userId,
+ callingUid);
} catch (PackageManager.NameNotFoundException e) {
return null;
}
@@ -6203,8 +6198,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
PersistableBundle appExtras, PersistableBundle launcherExtras,
- SuspendDialogInfo dialogInfo, int flags, String suspendingPackage,
- int suspendingUserId, int targetUserId) {
+ SuspendDialogInfo dialogInfo, int flags, String callingPackage, int userId) {
final int callingUid = Binder.getCallingUid();
boolean quarantined = false;
if (Flags.quarantinedEnabled()) {
@@ -6213,15 +6207,14 @@ public class PackageManagerService implements PackageSender, TestUtilityService
} else if (FeatureFlagUtils.isEnabled(mContext,
SETTINGS_TREAT_PAUSE_AS_QUARANTINE)) {
final String wellbeingPkg = mContext.getString(R.string.config_systemWellbeing);
- quarantined = suspendingPackage.equals(wellbeingPkg);
+ quarantined = callingPackage.equals(wellbeingPkg);
}
}
final Computer snapshot = snapshotComputer();
- final UserPackage suspender = UserPackage.of(targetUserId, suspendingPackage);
- enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, suspender, callingUid,
- targetUserId, "setPackagesSuspendedAsUser");
+ enforceCanSetPackagesSuspendedAsUser(snapshot, quarantined, callingPackage, callingUid,
+ userId, "setPackagesSuspendedAsUser");
return mSuspendPackageHelper.setPackagesSuspended(snapshot, packageNames, suspended,
- appExtras, launcherExtras, dialogInfo, suspender, targetUserId, callingUid,
+ appExtras, launcherExtras, dialogInfo, callingPackage, userId, callingUid,
quarantined);
}
@@ -6660,7 +6653,7 @@ public class PackageManagerService implements PackageSender, TestUtilityService
final Computer computer = snapshotComputer();
final String[] allPackages = computer.getAllAvailablePackageNames();
mSuspendPackageHelper.removeSuspensionsBySuspendingPackage(computer, allPackages,
- (suspender) -> !PLATFORM_PACKAGE_NAME.equals(suspender.packageName),
+ (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
userId);
}
@@ -6674,13 +6667,8 @@ public class PackageManagerService implements PackageSender, TestUtilityService
@Override
public String[] setPackagesSuspendedByAdmin(
@UserIdInt int userId, @NonNull String[] packageNames, boolean suspended) {
- final int suspendingUserId = userId;
- final UserPackage suspender = UserPackage.of(
- suspendingUserId, PackageManagerService.PLATFORM_PACKAGE_NAME);
- return mSuspendPackageHelper.setPackagesSuspended(snapshotComputer(), packageNames,
- suspended, null /* appExtras */, null /* launcherExtras */,
- null /* dialogInfo */, suspender, userId, Process.SYSTEM_UID,
- false /* quarantined */);
+ return mSuspendPackageHelper.setPackagesSuspendedByAdmin(
+ snapshotComputer(), userId, packageNames, suspended);
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 243fb16b19ae..322557b9e496 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2827,7 +2827,7 @@ class PackageManagerShellCommand extends ShellCommand {
mInterface.setPackagesSuspendedAsUser(packageNames.toArray(new String[] {}),
suspendedState, ((appExtras.size() > 0) ? appExtras : null),
((launcherExtras.size() > 0) ? launcherExtras : null),
- info, flags, callingPackage, UserHandle.USER_SYSTEM, translatedUserId);
+ info, flags, callingPackage, translatedUserId);
for (int i = 0; i < packageNames.size(); i++) {
final String packageName = packageNames.get(i);
pw.println("Package " + packageName + " new suspended state: "
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 28a90f3d6ab6..7d0a1f6afe1d 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -32,7 +32,6 @@ import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
-import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
@@ -953,7 +952,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
void setUserState(int userId, long ceDataInode, long deDataInode, int enabled,
boolean installed, boolean stopped, boolean notLaunched, boolean hidden,
- int distractionFlags, ArrayMap<UserPackage, SuspendParams> suspendParams,
+ int distractionFlags, ArrayMap<String, SuspendParams> suspendParams,
boolean instantApp, boolean virtualPreload, String lastDisableAppCaller,
ArraySet<String> enabledComponents, ArraySet<String> disabledComponents,
int installReason, int uninstallReason,
@@ -1183,7 +1182,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal
if (state.isSuspended()) {
for (int j = 0; j < state.getSuspendParams().size(); j++) {
proto.write(PackageProto.UserInfoProto.SUSPENDING_PACKAGE,
- state.getSuspendParams().keyAt(j).packageName);
+ state.getSuspendParams().keyAt(j));
}
}
proto.write(PackageProto.UserInfoProto.IS_STOPPED, state.isStopped());
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 9a7916a7b215..5e8778d3e29c 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -53,7 +53,7 @@ import java.util.Map;
* as install) led to the request.
*/
final class ReconcilePackageUtils {
- private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE || true;
+ private static final boolean ALLOW_NON_PRELOADS_SYSTEM_SIGNATURE = Build.IS_DEBUGGABLE;
public static List<ReconciledPackage> reconcilePackages(
List<InstallRequest> installRequests,
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index cdf1f949a2d8..460bbb7e4b41 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -51,7 +51,6 @@ import android.content.pm.ResolveInfo;
import android.content.pm.Signature;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
-import android.content.pm.UserPackage;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.overlay.OverlayPaths;
import android.net.Uri;
@@ -1957,7 +1956,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
ArchiveState archiveState = null;
int packageDepth = parser.getDepth();
- ArrayMap<UserPackage, SuspendParams> suspendParamsMap = null;
+ ArrayMap<String, SuspendParams> suspendParamsMap = null;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > packageDepth)) {
@@ -1984,15 +1983,18 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
parser);
break;
case TAG_SUSPEND_PARAMS:
- Map.Entry<UserPackage, SuspendParams> entry =
- readSuspensionParamsLPr(userId, parser);
- if (entry == null) {
+ final String suspendingPackage = parser.getAttributeValue(null,
+ ATTR_SUSPENDING_PACKAGE);
+ if (suspendingPackage == null) {
+ Slog.wtf(TAG, "No suspendingPackage found inside tag "
+ + TAG_SUSPEND_PARAMS);
continue;
}
if (suspendParamsMap == null) {
suspendParamsMap = new ArrayMap<>();
}
- suspendParamsMap.put(entry.getKey(), entry.getValue());
+ suspendParamsMap.put(suspendingPackage,
+ SuspendParams.restoreFromXml(parser));
break;
case TAG_ARCHIVE_STATE:
archiveState = parseArchiveState(parser);
@@ -2014,8 +2016,7 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
oldSuspendedLauncherExtras,
false /* quarantined */);
suspendParamsMap = new ArrayMap<>();
- suspendParamsMap.put(
- UserPackage.of(userId, oldSuspendingPackage), suspendParams);
+ suspendParamsMap.put(oldSuspendingPackage, suspendParams);
}
if (blockUninstall) {
@@ -2057,20 +2058,6 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
}
}
- @Nullable
- private static Map.Entry<UserPackage, SuspendParams> readSuspensionParamsLPr(
- int userId, TypedXmlPullParser parser) throws IOException {
- final String suspendingPackage = parser.getAttributeValue(null, ATTR_SUSPENDING_PACKAGE);
- if (suspendingPackage == null) {
- Slog.wtf(TAG, "No suspendingPackage found inside tag " + TAG_SUSPEND_PARAMS);
- return null;
- }
- final int suspendingUserId = userId;
- return Map.entry(
- UserPackage.of(suspendingUserId, suspendingPackage),
- SuspendParams.restoreFromXml(parser));
- }
-
private static ArchiveState parseArchiveState(TypedXmlPullParser parser)
throws XmlPullParserException, IOException {
String installerTitle = parser.getAttributeValue(null,
@@ -2427,11 +2414,10 @@ public final class Settings implements Watchable, Snappable, ResilientAtomicFile
}
if (ustate.isSuspended()) {
for (int i = 0; i < ustate.getSuspendParams().size(); i++) {
- final UserPackage suspendingPackage =
- ustate.getSuspendParams().keyAt(i);
+ final String suspendingPackage = ustate.getSuspendParams().keyAt(i);
serializer.startTag(null, TAG_SUSPEND_PARAMS);
serializer.attribute(null, ATTR_SUSPENDING_PACKAGE,
- suspendingPackage.packageName);
+ suspendingPackage);
final SuspendParams params =
ustate.getSuspendParams().valueAt(i);
if (params != null) {
diff --git a/services/core/java/com/android/server/pm/SuspendPackageHelper.java b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
index 4e70cc52ef90..c2a960a95394 100644
--- a/services/core/java/com/android/server/pm/SuspendPackageHelper.java
+++ b/services/core/java/com/android/server/pm/SuspendPackageHelper.java
@@ -27,10 +27,10 @@ import android.annotation.UserIdInt;
import android.app.AppOpsManager;
import android.content.Intent;
import android.content.pm.SuspendDialogInfo;
-import android.content.pm.UserPackage;
import android.os.Binder;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
@@ -88,8 +88,8 @@ public final class SuspendPackageHelper {
* @param dialogInfo An optional {@link SuspendDialogInfo} object describing the dialog that
* should be shown to the user when they try to launch a suspended app.
* Ignored if {@code suspended} is false.
- * @param suspendingPackage The caller's package name.
- * @param targetUserId The user where packages reside.
+ * @param callingPackage The caller's package name.
+ * @param userId The user where packages reside.
* @param callingUid The caller's uid.
* @return The names of failed packages.
*/
@@ -97,14 +97,14 @@ public final class SuspendPackageHelper {
String[] setPackagesSuspended(@NonNull Computer snapshot, @Nullable String[] packageNames,
boolean suspended, @Nullable PersistableBundle appExtras,
@Nullable PersistableBundle launcherExtras, @Nullable SuspendDialogInfo dialogInfo,
- @NonNull UserPackage suspendingPackage, @UserIdInt int targetUserId, int callingUid,
+ @NonNull String callingPackage, @UserIdInt int userId, int callingUid,
boolean quarantined) {
if (ArrayUtils.isEmpty(packageNames)) {
return packageNames;
}
- if (suspended && !quarantined
- && !isSuspendAllowedForUser(snapshot, targetUserId, callingUid)) {
- Slog.w(TAG, "Cannot suspend due to restrictions on user " + targetUserId);
+ if (suspended && !quarantined && !isSuspendAllowedForUser(snapshot, userId,
+ callingUid)) {
+ Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
return packageNames;
}
@@ -119,21 +119,19 @@ public final class SuspendPackageHelper {
final IntArray changedUids = new IntArray(packageNames.length);
final boolean[] canSuspend = suspended
- ? canSuspendPackageForUser(snapshot, packageNames, targetUserId, callingUid)
+ ? canSuspendPackageForUser(snapshot, packageNames, userId, callingUid)
: null;
for (int i = 0; i < packageNames.length; i++) {
final String packageName = packageNames[i];
- if (suspendingPackage.packageName.equals(packageName)
- && suspendingPackage.userId == targetUserId) {
- Slog.w(TAG, "Suspending package: " + suspendingPackage + " trying to "
+ if (callingPackage.equals(packageName)) {
+ Slog.w(TAG, "Calling package: " + callingPackage + " trying to "
+ (suspended ? "" : "un") + "suspend itself. Ignoring");
unmodifiablePackages.add(packageName);
continue;
}
final PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
- if (packageState == null
- || !packageState.getUserStateOrDefault(targetUserId).isInstalled()
- || snapshot.shouldFilterApplication(packageState, callingUid, targetUserId)) {
+ if (packageState == null || !packageState.getUserStateOrDefault(userId).isInstalled()
+ || snapshot.shouldFilterApplication(packageState, callingUid, userId)) {
Slog.w(TAG, "Could not find package setting for package: " + packageName
+ ". Skipping suspending/un-suspending.");
unmodifiablePackages.add(packageName);
@@ -144,34 +142,34 @@ public final class SuspendPackageHelper {
continue;
}
- final WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
- packageState.getUserStateOrDefault(targetUserId).getSuspendParams();
+ final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
+ packageState.getUserStateOrDefault(userId).getSuspendParams();
final SuspendParams oldSuspendParams = suspendParamsMap == null
- ? null : suspendParamsMap.get(suspendingPackage);
+ ? null : suspendParamsMap.get(callingPackage);
boolean changed = !Objects.equals(oldSuspendParams, newSuspendParams);
if (suspended && !changed) {
// Carried over API behavior, must notify change even if no change
notifyPackagesList.add(packageName);
notifyUids.add(
- UserHandle.getUid(targetUserId, packageState.getAppId()));
+ UserHandle.getUid(userId, packageState.getAppId()));
continue;
}
- // If only the suspendingPackage is suspending this package,
+ // If only the callingPackage is suspending this package,
// it will be unsuspended when this change is committed
boolean packageUnsuspended = !suspended
&& CollectionUtils.size(suspendParamsMap) == 1
- && suspendParamsMap.containsKey(suspendingPackage);
+ && suspendParamsMap.containsKey(callingPackage);
if (suspended || packageUnsuspended) {
// Always notify of a suspend call + notify when fully unsuspended
notifyPackagesList.add(packageName);
- notifyUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
+ notifyUids.add(UserHandle.getUid(userId, packageState.getAppId()));
}
if (changed) {
changedPackagesList.add(packageName);
- changedUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
+ changedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
} else {
Slog.w(TAG, "No change is needed for package: " + packageName
+ ". Skipping suspending/un-suspending.");
@@ -183,11 +181,11 @@ public final class SuspendPackageHelper {
for (int index = 0; index < size; index++) {
final String packageName = changedPackagesList.valueAt(index);
final PackageUserStateWrite userState = mutator.forPackage(packageName)
- .userState(targetUserId);
+ .userState(userId);
if (suspended) {
- userState.putSuspendParams(suspendingPackage, newSuspendParams);
+ userState.putSuspendParams(callingPackage, newSuspendParams);
} else {
- userState.removeSuspension(suspendingPackage);
+ userState.removeSuspension(callingPackage);
}
}
});
@@ -199,17 +197,17 @@ public final class SuspendPackageHelper {
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
suspended ? Intent.ACTION_PACKAGES_SUSPENDED
: Intent.ACTION_PACKAGES_UNSUSPENDED,
- changedPackages, notifyUids.toArray(), quarantined, targetUserId);
+ changedPackages, notifyUids.toArray(), quarantined, userId);
mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, changedPackages,
- suspended, targetUserId);
- mPm.scheduleWritePackageRestrictions(targetUserId);
+ suspended, userId);
+ mPm.scheduleWritePackageRestrictions(userId);
}
// Send the suspension changed broadcast to ensure suspension state is not stale.
if (!changedPackagesList.isEmpty()) {
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
Intent.ACTION_PACKAGES_SUSPENSION_CHANGED,
changedPackagesList.toArray(new String[0]), changedUids.toArray(), quarantined,
- targetUserId);
+ userId);
}
return unmodifiablePackages.toArray(new String[0]);
}
@@ -218,19 +216,19 @@ public final class SuspendPackageHelper {
* Returns the names in the {@code packageNames} which can not be suspended by the caller.
*
* @param packageNames The names of packages to check.
- * @param targetUserId The user where packages reside.
+ * @param userId The user where packages reside.
* @param callingUid The caller's uid.
* @return The names of packages which are Unsuspendable.
*/
@NonNull
String[] getUnsuspendablePackagesForUser(@NonNull Computer snapshot,
- @NonNull String[] packageNames, @UserIdInt int targetUserId, int callingUid) {
- if (!isSuspendAllowedForUser(snapshot, targetUserId, callingUid)) {
- Slog.w(TAG, "Cannot suspend due to restrictions on user " + targetUserId);
+ @NonNull String[] packageNames, @UserIdInt int userId, int callingUid) {
+ if (!isSuspendAllowedForUser(snapshot, userId, callingUid)) {
+ Slog.w(TAG, "Cannot suspend due to restrictions on user " + userId);
return packageNames;
}
final ArraySet<String> unactionablePackages = new ArraySet<>();
- final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, targetUserId,
+ final boolean[] canSuspend = canSuspendPackageForUser(snapshot, packageNames, userId,
callingUid);
for (int i = 0; i < packageNames.length; i++) {
if (!canSuspend[i]) {
@@ -239,7 +237,7 @@ public final class SuspendPackageHelper {
}
final PackageStateInternal packageState =
snapshot.getPackageStateForInstalledAndFiltered(
- packageNames[i], callingUid, targetUserId);
+ packageNames[i], callingUid, userId);
if (packageState == null) {
Slog.w(TAG, "Could not find package setting for package: " + packageNames[i]);
unactionablePackages.add(packageNames[i]);
@@ -287,31 +285,30 @@ public final class SuspendPackageHelper {
* @param packagesToChange The packages on which the suspension are to be removed.
* @param suspendingPackagePredicate A predicate identifying the suspending packages whose
* suspensions will be removed.
- * @param targetUserId The user for which the changes are taking place.
+ * @param userId The user for which the changes are taking place.
*/
void removeSuspensionsBySuspendingPackage(@NonNull Computer snapshot,
@NonNull String[] packagesToChange,
- @NonNull Predicate<UserPackage> suspendingPackagePredicate, int targetUserId) {
+ @NonNull Predicate<String> suspendingPackagePredicate, int userId) {
final List<String> unsuspendedPackages = new ArrayList<>();
final IntArray unsuspendedUids = new IntArray();
- final ArrayMap<String, ArraySet<UserPackage>> pkgToSuspendingPkgsToCommit =
- new ArrayMap<>();
+ final ArrayMap<String, ArraySet<String>> pkgToSuspendingPkgsToCommit = new ArrayMap<>();
for (String packageName : packagesToChange) {
final PackageStateInternal packageState =
snapshot.getPackageStateInternal(packageName);
final PackageUserStateInternal packageUserState = packageState == null
- ? null : packageState.getUserStateOrDefault(targetUserId);
+ ? null : packageState.getUserStateOrDefault(userId);
if (packageUserState == null || !packageUserState.isSuspended()) {
continue;
}
- WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
+ WatchedArrayMap<String, SuspendParams> suspendParamsMap =
packageUserState.getSuspendParams();
int countRemoved = 0;
for (int index = 0; index < suspendParamsMap.size(); index++) {
- UserPackage suspendingPackage = suspendParamsMap.keyAt(index);
+ String suspendingPackage = suspendParamsMap.keyAt(index);
if (suspendingPackagePredicate.test(suspendingPackage)) {
- ArraySet<UserPackage> suspendingPkgsToCommit =
+ ArraySet<String> suspendingPkgsToCommit =
pkgToSuspendingPkgsToCommit.get(packageName);
if (suspendingPkgsToCommit == null) {
suspendingPkgsToCommit = new ArraySet<>();
@@ -325,33 +322,31 @@ public final class SuspendPackageHelper {
// Everything would be removed and package unsuspended
if (countRemoved == suspendParamsMap.size()) {
unsuspendedPackages.add(packageState.getPackageName());
- unsuspendedUids.add(UserHandle.getUid(targetUserId, packageState.getAppId()));
+ unsuspendedUids.add(UserHandle.getUid(userId, packageState.getAppId()));
}
}
mPm.commitPackageStateMutation(null, mutator -> {
for (int mapIndex = 0; mapIndex < pkgToSuspendingPkgsToCommit.size(); mapIndex++) {
String packageName = pkgToSuspendingPkgsToCommit.keyAt(mapIndex);
- ArraySet<UserPackage> packagesToRemove =
- pkgToSuspendingPkgsToCommit.valueAt(mapIndex);
- PackageUserStateWrite userState =
- mutator.forPackage(packageName).userState(targetUserId);
+ ArraySet<String> packagesToRemove = pkgToSuspendingPkgsToCommit.valueAt(mapIndex);
+ PackageUserStateWrite userState = mutator.forPackage(packageName).userState(userId);
for (int setIndex = 0; setIndex < packagesToRemove.size(); setIndex++) {
userState.removeSuspension(packagesToRemove.valueAt(setIndex));
}
}
});
- mPm.scheduleWritePackageRestrictions(targetUserId);
+ mPm.scheduleWritePackageRestrictions(userId);
final Computer newSnapshot = mPm.snapshotComputer();
if (!unsuspendedPackages.isEmpty()) {
final String[] packageArray = unsuspendedPackages.toArray(
new String[unsuspendedPackages.size()]);
mBroadcastHelper.sendMyPackageSuspendedOrUnsuspended(newSnapshot, packageArray,
- false, targetUserId);
+ false, userId);
mBroadcastHelper.sendPackagesSuspendedOrUnsuspendedForUser(newSnapshot,
Intent.ACTION_PACKAGES_UNSUSPENDED,
- packageArray, unsuspendedUids.toArray(), false, targetUserId);
+ packageArray, unsuspendedUids.toArray(), false, userId);
}
}
@@ -409,7 +404,7 @@ public final class SuspendPackageHelper {
* @return The name of suspending package.
*/
@Nullable
- UserPackage getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
+ String getSuspendingPackage(@NonNull Computer snapshot, @NonNull String suspendedPackage,
int userId, int callingUid) {
final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
@@ -422,13 +417,13 @@ public final class SuspendPackageHelper {
return null;
}
- UserPackage suspendingPackage = null;
- UserPackage suspendedBySystem = null;
- UserPackage qasPackage = null;
+ String suspendingPackage = null;
+ String suspendedBySystem = null;
+ String qasPackage = null;
for (int i = 0; i < userState.getSuspendParams().size(); i++) {
suspendingPackage = userState.getSuspendParams().keyAt(i);
var suspendParams = userState.getSuspendParams().valueAt(i);
- if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage.packageName)) {
+ if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
suspendedBySystem = suspendingPackage;
}
if (suspendParams.isQuarantined() && qasPackage == null) {
@@ -456,7 +451,7 @@ public final class SuspendPackageHelper {
*/
@Nullable
SuspendDialogInfo getSuspendedDialogInfo(@NonNull Computer snapshot,
- @NonNull String suspendedPackage, @NonNull UserPackage suspendingPackage, int userId,
+ @NonNull String suspendedPackage, @NonNull String suspendingPackage, int userId,
int callingUid) {
final PackageStateInternal packageState = snapshot.getPackageStateInternal(
suspendedPackage, callingUid);
@@ -469,7 +464,7 @@ public final class SuspendPackageHelper {
return null;
}
- final WatchedArrayMap<UserPackage, SuspendParams> suspendParamsMap =
+ final WatchedArrayMap<String, SuspendParams> suspendParamsMap =
userState.getSuspendParams();
if (suspendParamsMap == null) {
return null;
@@ -498,36 +493,34 @@ public final class SuspendPackageHelper {
* be suspended or not.
*
* @param packageNames The package names to check suspendability for.
- * @param targetUserId The user to check in
+ * @param userId The user to check in
* @param callingUid The caller's uid.
* @return An array containing results of the checks
*/
@NonNull
boolean[] canSuspendPackageForUser(@NonNull Computer snapshot, @NonNull String[] packageNames,
- int targetUserId, int callingUid) {
+ int userId, int callingUid) {
final boolean[] canSuspend = new boolean[packageNames.length];
- final boolean isCallerOwner =
- isCallerDeviceOrProfileOwner(snapshot, targetUserId, callingUid);
+ final boolean isCallerOwner = isCallerDeviceOrProfileOwner(snapshot, userId, callingUid);
final long token = Binder.clearCallingIdentity();
try {
final DefaultAppProvider defaultAppProvider = mInjector.getDefaultAppProvider();
- final String activeLauncherPackageName =
- defaultAppProvider.getDefaultHome(targetUserId);
- final String dialerPackageName = defaultAppProvider.getDefaultDialer(targetUserId);
+ final String activeLauncherPackageName = defaultAppProvider.getDefaultHome(userId);
+ final String dialerPackageName = defaultAppProvider.getDefaultDialer(userId);
final String requiredInstallerPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_INSTALLER, targetUserId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_INSTALLER, userId);
final String requiredUninstallerPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_UNINSTALLER, targetUserId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_UNINSTALLER, userId);
final String requiredVerifierPackage =
- getKnownPackageName(snapshot, KnownPackages.PACKAGE_VERIFIER, targetUserId);
+ getKnownPackageName(snapshot, KnownPackages.PACKAGE_VERIFIER, userId);
final String requiredPermissionControllerPackage =
getKnownPackageName(snapshot, KnownPackages.PACKAGE_PERMISSION_CONTROLLER,
- targetUserId);
+ userId);
for (int i = 0; i < packageNames.length; i++) {
canSuspend[i] = false;
final String packageName = packageNames[i];
- if (mPm.isPackageDeviceAdmin(packageName, targetUserId)) {
+ if (mPm.isPackageDeviceAdmin(packageName, userId)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": has an active device admin");
continue;
@@ -562,12 +555,12 @@ public final class SuspendPackageHelper {
+ "\": required for permissions management");
continue;
}
- if (mProtectedPackages.isPackageStateProtected(targetUserId, packageName)) {
+ if (mProtectedPackages.isPackageStateProtected(userId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": protected package");
continue;
}
- if (!isCallerOwner && snapshot.getBlockUninstall(targetUserId, packageName)) {
+ if (!isCallerOwner && snapshot.getBlockUninstall(userId, packageName)) {
Slog.w(TAG, "Cannot suspend package \"" + packageName
+ "\": blocked by admin");
continue;
@@ -579,7 +572,7 @@ public final class SuspendPackageHelper {
PackageStateInternal packageState = snapshot.getPackageStateInternal(packageName);
AndroidPackage pkg = packageState == null ? null : packageState.getPkg();
if (pkg != null) {
- final int uid = UserHandle.getUid(targetUserId, packageState.getAppId());
+ final int uid = UserHandle.getUid(userId, packageState.getAppId());
// Cannot suspend SDK libs as they are controlled by SDK manager.
if (pkg.isSdkLibrary()) {
Slog.w(TAG, "Cannot suspend package: " + packageName
@@ -621,6 +614,20 @@ public final class SuspendPackageHelper {
== AppOpsManager.MODE_ALLOWED;
}
+ /**
+ * Suspends packages on behalf of an admin.
+ *
+ * @return array of packages that are unsuspendable, either because admin is not allowed to
+ * suspend them (e.g. current dialer) or there was other problem (e.g. package not found).
+ */
+ public String[] setPackagesSuspendedByAdmin(
+ Computer snapshot, int userId, String[] packageNames, boolean suspend) {
+ return setPackagesSuspended(snapshot, packageNames, suspend,
+ null /* appExtras */, null /* launcherExtras */, null /* dialogInfo */,
+ PackageManagerService.PLATFORM_PACKAGE_NAME, userId, Process.SYSTEM_UID,
+ false /* quarantined */);
+ }
+
private String getKnownPackageName(@NonNull Computer snapshot,
@KnownPackages.KnownPackage int knownPackage, int userId) {
final String[] knownPackages =
@@ -628,15 +635,14 @@ public final class SuspendPackageHelper {
return knownPackages.length > 0 ? knownPackages[0] : null;
}
- private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int targetUserId,
+ private boolean isCallerDeviceOrProfileOwner(@NonNull Computer snapshot, int userId,
int callingUid) {
if (callingUid == SYSTEM_UID) {
return true;
}
- final String ownerPackage =
- mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(targetUserId);
+ final String ownerPackage = mProtectedPackages.getDeviceOwnerOrProfileOwnerPackage(userId);
if (ownerPackage != null) {
- return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, targetUserId,
+ return callingUid == snapshot.getPackageUidInternal(ownerPackage, 0, userId,
callingUid);
}
return false;
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
index 15b693cf72f8..2f4ad2d8fcc6 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateDefault.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
-import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.util.ArraySet;
import android.util.Pair;
@@ -174,7 +173,7 @@ class PackageUserStateDefault implements PackageUserStateInternal {
@Nullable
@Override
- public WatchedArrayMap<UserPackage, SuspendParams> getSuspendParams() {
+ public WatchedArrayMap<String, SuspendParams> getSuspendParams() {
return null;
}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index 7a5a14d8d3c2..c5ef5257ddd5 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -22,7 +22,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
-import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -122,7 +121,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
@Nullable
- private WatchedArrayMap<UserPackage, SuspendParams> mSuspendParams;
+ private WatchedArrayMap<String, SuspendParams> mSuspendParams;
@Nullable
private WatchedArrayMap<ComponentName, Pair<String, Integer>> mComponentLabelIconOverrideMap;
@@ -370,10 +369,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
return !CollectionUtils.isEmpty(mSuspendParams);
}
- /**
- * Adds or updates suspension params by the given package.
- */
- public PackageUserStateImpl putSuspendParams(@NonNull UserPackage suspendingPackage,
+ public PackageUserStateImpl putSuspendParams(@NonNull String suspendingPackage,
@Nullable SuspendParams suspendParams) {
if (mSuspendParams == null) {
mSuspendParams = new WatchedArrayMap<>();
@@ -388,10 +384,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
return this;
}
- /**
- * Removes suspension by the given package.
- */
- public PackageUserStateImpl removeSuspension(@NonNull UserPackage suspendingPackage) {
+ public PackageUserStateImpl removeSuspension(@NonNull String suspendingPackage) {
if (mSuspendParams != null) {
mSuspendParams.remove(suspendingPackage);
onChanged();
@@ -572,7 +565,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
public @NonNull PackageUserStateImpl setSuspendParams(
- @NonNull ArrayMap<UserPackage, SuspendParams> value) {
+ @NonNull ArrayMap<String, SuspendParams> value) {
if (value == null) {
return this;
}
@@ -785,7 +778,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
@DataClass.Generated.Member
- public @Nullable WatchedArrayMap<UserPackage,SuspendParams> getSuspendParams() {
+ public @Nullable WatchedArrayMap<String,SuspendParams> getSuspendParams() {
return mSuspendParams;
}
@@ -837,7 +830,7 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
* Suspending package to suspend params
*/
@DataClass.Generated.Member
- public @NonNull PackageUserStateImpl setSuspendParams(@NonNull WatchedArrayMap<UserPackage,SuspendParams> value) {
+ public @NonNull PackageUserStateImpl setSuspendParams(@NonNull WatchedArrayMap<String,SuspendParams> value) {
mSuspendParams = value;
return this;
}
@@ -916,10 +909,10 @@ public class PackageUserStateImpl extends WatchableImpl implements PackageUserSt
}
@DataClass.Generated(
- time = 1701864813354L,
+ time = 1701470095849L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
- inputSignatures = "private int mBooleans\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate long mDeDataInode\nprivate int mDistractionFlags\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.pm.UserPackage,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(android.content.pm.UserPackage,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(android.content.pm.UserPackage)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<android.content.pm.UserPackage,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isQuarantined()\npublic @java.lang.Override boolean dataExists()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\nprivate static final int INSTALLED\nprivate static final int STOPPED\nprivate static final int NOT_LAUNCHED\nprivate static final int HIDDEN\nprivate static final int INSTANT_APP\nprivate static final int VIRTUAL_PRELOADED\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+ inputSignatures = "private int mBooleans\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate long mCeDataInode\nprivate long mDeDataInode\nprivate int mDistractionFlags\nprivate @android.content.pm.PackageManager.EnabledState int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.content.pm.PackageManager.UserMinAspectRatio int mMinAspectRatio\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate @android.annotation.CurrentTimeMillisLong long mFirstInstallTimeMillis\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nprivate @android.annotation.Nullable com.android.server.pm.pkg.ArchiveState mArchiveState\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate void setBoolean(int,boolean)\nprivate boolean getBoolean(int)\nprivate com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setMinAspectRatio(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTimeMillis(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setArchiveState(com.android.server.pm.pkg.ArchiveState)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate boolean watchableEquals(com.android.server.utils.Watchable)\nprivate int watchableHashCode()\nprivate boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate int snapshotHashCode()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isQuarantined()\npublic @java.lang.Override boolean dataExists()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\nprivate static final int INSTALLED\nprivate static final int STOPPED\nprivate static final int NOT_LAUNCHED\nprivate static final int HIDDEN\nprivate static final int INSTANT_APP\nprivate static final int VIRTUAL_PRELOADED\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
@Deprecated
private void __metadata() {}
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
index f8d745cb7fbf..46cc830130ef 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateInternal.java
@@ -19,7 +19,6 @@ package com.android.server.pm.pkg;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
-import android.content.pm.UserPackage;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.util.Pair;
@@ -39,7 +38,7 @@ public interface PackageUserStateInternal extends PackageUserState, FrameworkPac
// TODO: Make non-null with emptyMap()
@Nullable
- WatchedArrayMap<UserPackage, SuspendParams> getSuspendParams();
+ WatchedArrayMap<String, SuspendParams> getSuspendParams();
@Nullable
WatchedArraySet<String> getDisabledComponentsNoCopy();
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
index 253eb4006122..8430cf7a0d11 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
@@ -21,7 +21,6 @@ import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
-import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.util.ArraySet;
@@ -350,7 +349,7 @@ public class PackageStateMutator {
@NonNull
@Override
- public PackageUserStateWrite putSuspendParams(@NonNull UserPackage suspendingPackage,
+ public PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
@Nullable SuspendParams suspendParams) {
if (mUserState != null) {
mUserState.putSuspendParams(suspendingPackage, suspendParams);
@@ -360,7 +359,7 @@ public class PackageStateMutator {
@NonNull
@Override
- public PackageUserStateWrite removeSuspension(@NonNull UserPackage suspendingPackage) {
+ public PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage) {
if (mUserState != null) {
mUserState.removeSuspension(suspendingPackage);
}
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
index f6b21045a8bb..0c6c6723b79b 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageUserStateWrite.java
@@ -20,7 +20,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager;
-import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import com.android.server.pm.pkg.PackageUserStateImpl;
@@ -39,11 +38,11 @@ public interface PackageUserStateWrite {
@PackageManager.DistractionRestriction int restrictionFlags);
@NonNull
- PackageUserStateWrite putSuspendParams(@NonNull UserPackage suspendingPackage,
+ PackageUserStateWrite putSuspendParams(@NonNull String suspendingPackage,
@Nullable SuspendParams suspendParams);
@NonNull
- PackageUserStateWrite removeSuspension(@NonNull UserPackage suspendingPackage);
+ PackageUserStateWrite removeSuspension(@NonNull String suspendingPackage);
@NonNull
PackageUserStateWrite setHidden(boolean hidden);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 2df965c5a83f..f3922f9917ba 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -182,6 +182,7 @@ import static com.android.server.wm.ActivityRecordProto.PROVIDES_MAX_BOUNDS;
import static com.android.server.wm.ActivityRecordProto.REPORTED_DRAWN;
import static com.android.server.wm.ActivityRecordProto.REPORTED_VISIBLE;
import static com.android.server.wm.ActivityRecordProto.SHOULD_FORCE_ROTATE_FOR_CAMERA_COMPAT;
+import static com.android.server.wm.ActivityRecordProto.SHOULD_OVERRIDE_MIN_ASPECT_RATIO;
import static com.android.server.wm.ActivityRecordProto.SHOULD_REFRESH_ACTIVITY_FOR_CAMERA_COMPAT;
import static com.android.server.wm.ActivityRecordProto.SHOULD_REFRESH_ACTIVITY_VIA_PAUSE_FOR_CAMERA_COMPAT;
import static com.android.server.wm.ActivityRecordProto.SHOULD_SEND_COMPAT_FAKE_FOCUS;
@@ -10357,6 +10358,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
mLetterboxUiController.shouldRefreshActivityForCameraCompat());
proto.write(SHOULD_REFRESH_ACTIVITY_VIA_PAUSE_FOR_CAMERA_COMPAT,
mLetterboxUiController.shouldRefreshActivityViaPauseForCameraCompat());
+ proto.write(SHOULD_OVERRIDE_MIN_ASPECT_RATIO,
+ mLetterboxUiController.shouldOverrideMinAspectRatio());
}
@Override
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index 1b45c1b4f3f1..f9d344bd7e31 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -48,7 +48,6 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
-import android.content.pm.UserPackage;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -336,19 +335,19 @@ class ActivityStartInterceptor {
return false;
}
final String suspendedPackage = mAInfo.applicationInfo.packageName;
- final UserPackage suspender = pmi.getSuspendingPackage(suspendedPackage, mUserId);
- if (suspender != null && PLATFORM_PACKAGE_NAME.equals(suspender.packageName)) {
+ final String suspendingPackage = pmi.getSuspendingPackage(suspendedPackage, mUserId);
+ if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
return interceptSuspendedByAdminPackage();
}
final SuspendDialogInfo dialogInfo = pmi.getSuspendedDialogInfo(suspendedPackage,
- suspender, mUserId);
+ suspendingPackage, mUserId);
final Bundle crossProfileOptions = hasCrossProfileAnimation()
? ActivityOptions.makeOpenCrossProfileAppsAnimation().toBundle()
: null;
final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
FLAG_IMMUTABLE);
mIntent = SuspendedAppActivity.createSuspendedAppInterceptIntent(suspendedPackage,
- suspender, dialogInfo, crossProfileOptions, target, mUserId);
+ suspendingPackage, dialogInfo, crossProfileOptions, target, mUserId);
mCallingPid = mRealCallingPid;
mCallingUid = mRealCallingUid;
mResolvedType = null;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 869bcc0f9b8f..38682caaa036 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3695,6 +3695,21 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
boolean originallyFromClient = fromClient
&& (!r.isState(PAUSING) || params.isAutoEnterEnabled());
+ // If PiP2 flag is on and client-request to enter PiP came via onUserLeaveHint(),
+ // we request a direct transition from Shell to TRANSIT_PIP_LEGACY to get the startWct
+ // with the right entry bounds.
+ if (isPip2ExperimentEnabled() && !originallyFromClient && !params.isAutoEnterEnabled()) {
+ final Transition legacyEnterPipTransition = new Transition(TRANSIT_PIP,
+ 0 /* flags */, getTransitionController(),
+ mWindowManager.mSyncEngine);
+ legacyEnterPipTransition.setPipActivity(r);
+ getTransitionController().startCollectOrQueue(legacyEnterPipTransition, (deferred) -> {
+ getTransitionController().requestStartTransition(legacyEnterPipTransition,
+ r.getTask(), null /* remoteTransition */, null /* displayChange */);
+ });
+ return true;
+ }
+
// Create a transition only for this pip entry if it is coming from the app without the
// system requesting that the app enter-pip. If the system requested it, that means it
// should be part of that transition if possible.
diff --git a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
index e91857f1da82..735c73a990cb 100644
--- a/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
+++ b/services/core/java/com/android/server/wm/DimmerAnimationHelper.java
@@ -171,12 +171,14 @@ public class DimmerAnimationHelper {
mLocalAnimationAdapter.startAnimation(dim.mDimSurface, t,
ANIMATION_TYPE_DIMMER, /* finishCallback */ (type, animator) -> {
- setAlphaBlur(dim.mDimSurface, targetAlpha, targetBlur, t);
- if (targetAlpha == 0f && !dim.isDimming()) {
- dim.remove(t);
+ synchronized (dim.mHostContainer.mWmService.mGlobalLock) {
+ setAlphaBlur(dim.mDimSurface, targetAlpha, targetBlur, t);
+ if (targetAlpha == 0f && !dim.isDimming()) {
+ dim.remove(t);
+ }
+ mLocalAnimationAdapter = null;
+ mAlphaAnimationSpec = null;
}
- mLocalAnimationAdapter = null;
- mAlphaAnimationSpec = null;
});
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index e648d6417e88..c3aca6fe84d1 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -731,9 +731,9 @@ class TransitionController {
}
// set the pip task in the request if provided
- if (mCollectingTransition.getPipActivity() != null) {
- pipTaskInfo = mCollectingTransition.getPipActivity().getTask().getTaskInfo();
- mCollectingTransition.setPipActivity(null);
+ if (transition.getPipActivity() != null) {
+ pipTaskInfo = transition.getPipActivity().getTask().getTaskInfo();
+ transition.setPipActivity(null);
}
final TransitionRequestInfo request = new TransitionRequestInfo(transition.mType,
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index bc05e77171bd..0dd0564ae034 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -2747,6 +2747,14 @@ static void nativeSetAccessibilityBounceKeysThreshold(JNIEnv* env, jobject nativ
}
}
+static void nativeSetAccessibilityStickyKeysEnabled(JNIEnv* env, jobject nativeImplObj,
+ jboolean enabled) {
+ NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+ if (ENABLE_INPUT_FILTER_RUST) {
+ im->getInputManager()->getInputFilter().setAccessibilityStickyKeysEnabled(enabled);
+ }
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gInputManagerMethods[] = {
@@ -2848,6 +2856,8 @@ static const JNINativeMethod gInputManagerMethods[] = {
{"setStylusPointerIconEnabled", "(Z)V", (void*)nativeSetStylusPointerIconEnabled},
{"setAccessibilityBounceKeysThreshold", "(I)V",
(void*)nativeSetAccessibilityBounceKeysThreshold},
+ {"setAccessibilityStickyKeysEnabled", "(Z)V",
+ (void*)nativeSetAccessibilityStickyKeysEnabled},
};
#define FIND_CLASS(var, className) \
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index a490013303e9..e0a2f30b1831 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2469,7 +2469,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void migratePersonalAppSuspensionLocked(
int doUserId, int poUserId, ActiveAdmin poAdmin) {
final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
- if (!pmi.isAdminSuspendingAnyPackages(doUserId)) {
+ if (!pmi.isSuspendingAnyPackages(PLATFORM_PACKAGE_NAME, doUserId)) {
Slogf.i(LOG_TAG, "DO is not suspending any apps.");
return;
}
@@ -2480,7 +2480,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
poAdmin.mSuspendPersonalApps = true;
} else {
Slogf.i(LOG_TAG, "PO isn't targeting R+, unsuspending personal apps.");
- pmi.unsuspendAdminSuspendedPackages(doUserId);
+ pmi.unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, doUserId);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 506dbe8c48c4..6570ce1cd500 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -16,6 +16,8 @@
package com.android.server.devicepolicy;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppGlobals;
@@ -285,7 +287,7 @@ final class PolicyEnforcerCallbacks {
suspendPersonalAppsInPackageManager(context, userId);
} else {
LocalServices.getService(PackageManagerInternal.class)
- .unsuspendAdminSuspendedPackages(userId);
+ .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, userId);
}
});
return true;
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
index 40d3d5ca9fd9..3d0b389aa171 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -50,7 +50,6 @@ import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
-import android.content.pm.UserPackage;
import android.os.BaseBundle;
import android.os.Message;
import android.os.PersistableBundle;
@@ -426,7 +425,7 @@ public class PackageManagerSettingsTests {
PackageUserStateInternal packageUserState1 = ps1.readUserState(0);
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is(UserPackage.of(0, "android")));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is("android"));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getAppExtras(), is(nullValue()));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getDialogInfo(),
is(nullValue()));
@@ -438,7 +437,7 @@ public class PackageManagerSettingsTests {
packageUserState1 = ps1.readUserState(0);
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0), is(UserPackage.of(0, "android")));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is("android"));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getAppExtras(), is(nullValue()));
assertThat(packageUserState1.getSuspendParams().valueAt(0).getDialogInfo(),
is(nullValue()));
@@ -473,8 +472,7 @@ public class PackageManagerSettingsTests {
watcher.verifyNoChangeReported("readUserState");
assertThat(packageUserState1.isSuspended(), is(true));
assertThat(packageUserState1.getSuspendParams().size(), is(1));
- assertThat(packageUserState1.getSuspendParams().keyAt(0),
- is(UserPackage.of(0, PACKAGE_NAME_3)));
+ assertThat(packageUserState1.getSuspendParams().keyAt(0), is(PACKAGE_NAME_3));
final SuspendParams params = packageUserState1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("fetch user state");
assertThat(params, is(notNullValue()));
@@ -525,24 +523,19 @@ public class PackageManagerSettingsTests {
.setNeutralButtonAction(BUTTON_ACTION_UNSUSPEND)
.build();
- UserPackage suspender1 = UserPackage.of(0, "suspendingPackage1");
- UserPackage suspender2 = UserPackage.of(0, "suspendingPackage2");
- UserPackage suspender3 = UserPackage.of(0, "suspendingPackage3");
- UserPackage irrelevantSuspender = UserPackage.of(0, "irrelevant");
-
- ps1.modifyUserState(0).putSuspendParams(suspender1,
+ ps1.modifyUserState(0).putSuspendParams("suspendingPackage1",
new SuspendParams(dialogInfo1, appExtras1, launcherExtras1));
- ps1.modifyUserState(0).putSuspendParams(suspender2,
+ ps1.modifyUserState(0).putSuspendParams("suspendingPackage2",
new SuspendParams(dialogInfo2, appExtras2, launcherExtras2));
settingsUnderTest.mPackages.put(PACKAGE_NAME_1, ps1);
watcher.verifyChangeReported("put package 1");
- ps2.modifyUserState(0).putSuspendParams(suspender3,
+ ps2.modifyUserState(0).putSuspendParams("suspendingPackage3",
new SuspendParams(null, appExtras1, null));
settingsUnderTest.mPackages.put(PACKAGE_NAME_2, ps2);
watcher.verifyChangeReported("put package 2");
- ps3.modifyUserState(0).removeSuspension(irrelevantSuspender);
+ ps3.modifyUserState(0).removeSuspension("irrelevant");
settingsUnderTest.mPackages.put(PACKAGE_NAME_3, ps3);
watcher.verifyChangeReported("put package 3");
@@ -567,7 +560,7 @@ public class PackageManagerSettingsTests {
assertThat(readPus1.getSuspendParams().size(), is(2));
watcher.verifyNoChangeReported("read package param");
- assertThat(readPus1.getSuspendParams().keyAt(0), is(suspender1));
+ assertThat(readPus1.getSuspendParams().keyAt(0), is("suspendingPackage1"));
final SuspendParams params11 = readPus1.getSuspendParams().valueAt(0);
watcher.verifyNoChangeReported("read package param");
assertThat(params11, is(notNullValue()));
@@ -577,7 +570,7 @@ public class PackageManagerSettingsTests {
is(true));
watcher.verifyNoChangeReported("read package param");
- assertThat(readPus1.getSuspendParams().keyAt(1), is(suspender2));
+ assertThat(readPus1.getSuspendParams().keyAt(1), is("suspendingPackage2"));
final SuspendParams params12 = readPus1.getSuspendParams().valueAt(1);
assertThat(params12, is(notNullValue()));
assertThat(params12.getDialogInfo(), is(dialogInfo2));
@@ -590,7 +583,7 @@ public class PackageManagerSettingsTests {
.readUserState(0);
assertThat(readPus2.isSuspended(), is(true));
assertThat(readPus2.getSuspendParams().size(), is(1));
- assertThat(readPus2.getSuspendParams().keyAt(0), is(suspender3));
+ assertThat(readPus2.getSuspendParams().keyAt(0), is("suspendingPackage3"));
final SuspendParams params21 = readPus2.getSuspendParams().valueAt(0);
assertThat(params21, is(notNullValue()));
assertThat(params21.getDialogInfo(), is(nullValue()));
@@ -1141,8 +1134,7 @@ public class PackageManagerSettingsTests {
.setNeutralButtonText(0x11220003)
.setNeutralButtonAction(BUTTON_ACTION_MORE_DETAILS)
.build();
- origPkgSetting01.modifyUserState(0).putSuspendParams(
- UserPackage.of(0, "suspendingPackage1"),
+ origPkgSetting01.modifyUserState(0).putSuspendParams("suspendingPackage1",
new SuspendParams(dialogInfo1, appExtras1, launcherExtras1));
origPkgSetting01.setPkg(mockAndroidPackage(origPkgSetting01));
final PackageSetting testPkgSetting01 = new PackageSetting(
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
index 978044045ab3..c0c70321c79b 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageUserStateTest.java
@@ -27,7 +27,6 @@ import static org.junit.Assert.assertTrue;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.SuspendDialogInfo;
-import android.content.pm.UserPackage;
import android.content.pm.overlay.OverlayPaths;
import android.os.PersistableBundle;
import android.platform.test.annotations.Presubmit;
@@ -90,7 +89,7 @@ public class PackageUserStateTest {
assertThat(testUserState.equals(oldUserState), is(false));
oldUserState = new PackageUserStateImpl();
- oldUserState.putSuspendParams(UserPackage.of(0, "suspendingPackage"),
+ oldUserState.putSuspendParams("suspendingPackage",
new SuspendParams(null, new PersistableBundle(), null));
assertThat(testUserState.equals(oldUserState), is(false));
@@ -221,8 +220,6 @@ public class PackageUserStateTest {
final PersistableBundle launcherExtras2 = createPersistableBundle(null, 0, "name",
"launcherExtras2", null, 0);
- final int suspendingUser1 = 0;
- final int suspendingUser2 = 10;
final String suspendingPackage1 = "package1";
final String suspendingPackage2 = "package2";
@@ -233,12 +230,12 @@ public class PackageUserStateTest {
.setMessage("dialogMessage2")
.build();
- final ArrayMap<UserPackage, SuspendParams> paramsMap1 = new ArrayMap<>();
- paramsMap1.put(UserPackage.of(suspendingUser1, suspendingPackage1),
- createSuspendParams(dialogInfo1, appExtras1, launcherExtras1));
- final ArrayMap<UserPackage, SuspendParams> paramsMap2 = new ArrayMap<>();
- paramsMap2.put(UserPackage.of(suspendingUser2, suspendingPackage2),
- createSuspendParams(dialogInfo2, appExtras2, launcherExtras2));
+ final ArrayMap<String, SuspendParams> paramsMap1 = new ArrayMap<>();
+ paramsMap1.put(suspendingPackage1, createSuspendParams(dialogInfo1, appExtras1,
+ launcherExtras1));
+ final ArrayMap<String, SuspendParams> paramsMap2 = new ArrayMap<>();
+ paramsMap2.put(suspendingPackage2, createSuspendParams(dialogInfo2,
+ appExtras2, launcherExtras2));
final PackageUserStateImpl testUserState1 = new PackageUserStateImpl();
diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 2bdebe26e551..418b78cd696b 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -17,6 +17,8 @@
package com.android.server.display;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -39,7 +41,9 @@ import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.Handler;
+import android.os.PowerManager;
import android.os.test.TestLooper;
+import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -98,8 +102,8 @@ public class AutomaticBrightnessControllerTest {
mLightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor");
mContext = InstrumentationRegistry.getContext();
- setupController(BrightnessMappingStrategy.NO_USER_LUX,
- BrightnessMappingStrategy.NO_USER_BRIGHTNESS, /* applyDebounce= */ false,
+ setupController(BrightnessMappingStrategy.INVALID_LUX,
+ BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ false,
/* useHorizon= */ true);
}
@@ -112,11 +116,19 @@ public class AutomaticBrightnessControllerTest {
}
}
- private void setupController(float userLux, float userBrightness, boolean applyDebounce,
+ private void setupController(float userLux, float userNits, boolean applyDebounce,
boolean useHorizon) {
mClock = new OffsettableClock.Stopped();
mTestLooper = new TestLooper(mClock::now);
+ when(mBrightnessMappingStrategy.getMode()).thenReturn(AUTO_BRIGHTNESS_MODE_DEFAULT);
+ when(mIdleBrightnessMappingStrategy.getMode()).thenReturn(AUTO_BRIGHTNESS_MODE_IDLE);
+
+ SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap = new SparseArray<>();
+ brightnessMappingStrategyMap.append(AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mBrightnessMappingStrategy);
+ brightnessMappingStrategyMap.append(AUTO_BRIGHTNESS_MODE_IDLE,
+ mIdleBrightnessMappingStrategy);
mController = new AutomaticBrightnessController(
new AutomaticBrightnessController.Injector() {
@Override
@@ -131,7 +143,7 @@ public class AutomaticBrightnessControllerTest {
}, // pass in test looper instead, pass in offsettable clock
() -> { }, mTestLooper.getLooper(), mSensorManager, mLightSensor,
- mBrightnessMappingStrategy, LIGHT_SENSOR_WARMUP_TIME, BRIGHTNESS_MIN_FLOAT,
+ brightnessMappingStrategyMap, LIGHT_SENSOR_WARMUP_TIME, BRIGHTNESS_MIN_FLOAT,
BRIGHTNESS_MAX_FLOAT, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE,
INITIAL_LIGHT_SENSOR_RATE, applyDebounce ? BRIGHTENING_LIGHT_DEBOUNCE_CONFIG : 0,
applyDebounce ? DARKENING_LIGHT_DEBOUNCE_CONFIG : 0,
@@ -141,8 +153,8 @@ public class AutomaticBrightnessControllerTest {
mAmbientBrightnessThresholds, mScreenBrightnessThresholds,
mAmbientBrightnessThresholdsIdle, mScreenBrightnessThresholdsIdle,
mContext, mBrightnessRangeController, mBrightnessThrottler,
- mIdleBrightnessMappingStrategy, useHorizon ? AMBIENT_LIGHT_HORIZON_SHORT : 1,
- useHorizon ? AMBIENT_LIGHT_HORIZON_LONG : 10000, userLux, userBrightness
+ useHorizon ? AMBIENT_LIGHT_HORIZON_SHORT : 1,
+ useHorizon ? AMBIENT_LIGHT_HORIZON_LONG : 10000, userLux, userNits
);
when(mBrightnessRangeController.getCurrentBrightnessMax()).thenReturn(
@@ -326,8 +338,7 @@ public class AutomaticBrightnessControllerTest {
when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
- mController.switchToIdleMode();
- when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
when(mBrightnessMappingStrategy.shouldResetShortTermModel(
123f, 0.5f)).thenReturn(true);
@@ -337,7 +348,7 @@ public class AutomaticBrightnessControllerTest {
mBrightnessMappingStrategy.getShortTermModelTimeout() + 1000);
mTestLooper.dispatchAll();
- mController.switchToInteractiveScreenBrightnessMode();
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
mTestLooper.moveTimeForward(4000);
mTestLooper.dispatchAll();
@@ -371,15 +382,14 @@ public class AutomaticBrightnessControllerTest {
when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.51f);
when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123.0f);
- mController.switchToIdleMode();
- when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
// Time does not move forward, since clock is doesn't increment naturally.
mTestLooper.dispatchAll();
// Sensor reads 100000 lux,
listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 678910));
- mController.switchToInteractiveScreenBrightnessMode();
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
// Verify short term model is not reset.
verify(mBrightnessMappingStrategy, never()).clearUserDataPoints();
@@ -410,10 +420,11 @@ public class AutomaticBrightnessControllerTest {
when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.5f);
when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123f);
- mController.switchToIdleMode();
- when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
- when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(-1f);
- when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(-1f);
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+ when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(
+ BrightnessMappingStrategy.INVALID_LUX);
when(mBrightnessMappingStrategy.shouldResetShortTermModel(
123f, 0.5f)).thenReturn(true);
@@ -423,7 +434,7 @@ public class AutomaticBrightnessControllerTest {
mBrightnessMappingStrategy.getShortTermModelTimeout() + 1000);
mTestLooper.dispatchAll();
- mController.switchToInteractiveScreenBrightnessMode();
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
mTestLooper.moveTimeForward(4000);
mTestLooper.dispatchAll();
@@ -456,10 +467,11 @@ public class AutomaticBrightnessControllerTest {
when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.5f);
when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123f);
- mController.switchToIdleMode();
- when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
- when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(-1f);
- when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(-1f);
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+ when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(
+ BrightnessMappingStrategy.INVALID_LUX);
when(mBrightnessMappingStrategy.shouldResetShortTermModel(
123f, 0.5f)).thenReturn(true);
@@ -469,7 +481,7 @@ public class AutomaticBrightnessControllerTest {
// Do not fast-forward time.
mTestLooper.dispatchAll();
- mController.switchToInteractiveScreenBrightnessMode();
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
// Do not fast-forward time
mTestLooper.dispatchAll();
@@ -492,22 +504,25 @@ public class AutomaticBrightnessControllerTest {
// Sensor reads 123 lux,
listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 123));
when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
- when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(-1.0f);
- when(mBrightnessMappingStrategy.getUserLux()).thenReturn(-1.0f);
+ when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ when(mBrightnessMappingStrategy.getUserLux()).thenReturn(
+ BrightnessMappingStrategy.INVALID_LUX);
// No user brightness interaction.
- mController.switchToIdleMode();
- when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
- when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(-1.0f);
- when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(-1.0f);
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+ when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(
+ PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(
+ BrightnessMappingStrategy.INVALID_LUX);
// Sensor reads 1000 lux,
listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 1000));
// Do not fast-forward time.
mTestLooper.dispatchAll();
- mController.switchToInteractiveScreenBrightnessMode();
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
// Do not fast-forward time
mTestLooper.dispatchAll();
@@ -541,12 +556,12 @@ public class AutomaticBrightnessControllerTest {
verify(mBrightnessMappingStrategy, times(3)).getBrightness(anyFloat(), any(), anyInt());
// Now let's do the same for idle mode
- mController.switchToIdleMode();
- // Called once for init, and once when switching,
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+ // Called once when switching,
// setAmbientLux() is called twice and once in updateAutoBrightness(),
// nextAmbientLightBrighteningTransition() and nextAmbientLightDarkeningTransition() are
// called twice each.
- verify(mBrightnessMappingStrategy, times(9)).isForIdleMode();
+ verify(mBrightnessMappingStrategy, times(8)).getMode();
// Called when switching.
verify(mBrightnessMappingStrategy, times(1)).getShortTermModelTimeout();
verify(mBrightnessMappingStrategy, times(1)).getUserBrightness();
@@ -826,7 +841,6 @@ public class AutomaticBrightnessControllerTest {
@Test
public void testResetShortTermModelWhenConfigChanges() {
- when(mBrightnessMappingStrategy.isForIdleMode()).thenReturn(false);
when(mBrightnessMappingStrategy.setBrightnessConfiguration(any())).thenReturn(true);
mController.configure(AUTO_BRIGHTNESS_ENABLED, null /* configuration= */,
@@ -847,8 +861,10 @@ public class AutomaticBrightnessControllerTest {
verify(mBrightnessMappingStrategy, never()).addUserDataPoint(anyFloat(), anyFloat());
float userLux = 1000;
+ float userNits = 500;
float userBrightness = 0.3f;
- setupController(userLux, userBrightness, /* applyDebounce= */ true,
+ when(mBrightnessMappingStrategy.getBrightnessFromNits(userNits)).thenReturn(userBrightness);
+ setupController(userLux, userNits, /* applyDebounce= */ true,
/* useHorizon= */ false);
verify(mBrightnessMappingStrategy).addUserDataPoint(userLux, userBrightness);
}
@@ -856,8 +872,8 @@ public class AutomaticBrightnessControllerTest {
@Test
public void testBrighteningLightDebounce() throws Exception {
clearInvocations(mSensorManager);
- setupController(BrightnessMappingStrategy.NO_USER_LUX,
- BrightnessMappingStrategy.NO_USER_BRIGHTNESS, /* applyDebounce= */ true,
+ setupController(BrightnessMappingStrategy.INVALID_LUX,
+ BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ true,
/* useHorizon= */ false);
ArgumentCaptor<SensorEventListener> listenerCaptor =
@@ -897,8 +913,8 @@ public class AutomaticBrightnessControllerTest {
.thenReturn(10000f);
when(mAmbientBrightnessThresholds.getDarkeningThreshold(anyFloat()))
.thenReturn(10000f);
- setupController(BrightnessMappingStrategy.NO_USER_LUX,
- BrightnessMappingStrategy.NO_USER_BRIGHTNESS, /* applyDebounce= */ true,
+ setupController(BrightnessMappingStrategy.INVALID_LUX,
+ BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ true,
/* useHorizon= */ false);
ArgumentCaptor<SensorEventListener> listenerCaptor =
@@ -934,12 +950,11 @@ public class AutomaticBrightnessControllerTest {
@Test
public void testBrighteningLightDebounceIdle() throws Exception {
clearInvocations(mSensorManager);
- setupController(BrightnessMappingStrategy.NO_USER_LUX,
- BrightnessMappingStrategy.NO_USER_BRIGHTNESS, /* applyDebounce= */ true,
+ setupController(BrightnessMappingStrategy.INVALID_LUX,
+ BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ true,
/* useHorizon= */ false);
- mController.switchToIdleMode();
- when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
ArgumentCaptor<SensorEventListener> listenerCaptor =
ArgumentCaptor.forClass(SensorEventListener.class);
@@ -972,12 +987,11 @@ public class AutomaticBrightnessControllerTest {
.thenReturn(10000f);
when(mAmbientBrightnessThresholdsIdle.getDarkeningThreshold(anyFloat()))
.thenReturn(10000f);
- setupController(BrightnessMappingStrategy.NO_USER_LUX,
- BrightnessMappingStrategy.NO_USER_BRIGHTNESS, /* applyDebounce= */ true,
+ setupController(BrightnessMappingStrategy.INVALID_LUX,
+ BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ true,
/* useHorizon= */ false);
- mController.switchToIdleMode();
- when(mIdleBrightnessMappingStrategy.isForIdleMode()).thenReturn(true);
+ mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
ArgumentCaptor<SensorEventListener> listenerCaptor =
ArgumentCaptor.forClass(SensorEventListener.class);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index a2e80f0d9b9b..189d9bbfe806 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -16,6 +16,9 @@
package com.android.server.display;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
@@ -172,7 +175,9 @@ public class BrightnessMappingStrategyTest {
public void testSimpleStrategyMappingAtControlPoints_IntConfig() {
Resources res = createResources(DISPLAY_LEVELS_INT);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mMockDwbc);
assertNotNull("BrightnessMappingStrategy should not be null", simple);
for (int i = 0; i < LUX_LEVELS.length; i++) {
final float expectedLevel = MathUtils.map(PowerManager.BRIGHTNESS_OFF + 1,
@@ -187,7 +192,9 @@ public class BrightnessMappingStrategyTest {
public void testSimpleStrategyMappingBetweenControlPoints_IntConfig() {
Resources res = createResources(DISPLAY_LEVELS_INT);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mMockDwbc);
assertNotNull("BrightnessMappingStrategy should not be null", simple);
for (int i = 1; i < LUX_LEVELS.length; i++) {
final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
@@ -203,7 +210,9 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(EMPTY_INT_ARRAY);
DisplayDeviceConfig ddc = createDdc(EMPTY_FLOAT_ARRAY, EMPTY_FLOAT_ARRAY, LUX_LEVELS,
EMPTY_FLOAT_ARRAY, DISPLAY_LEVELS);
- BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mMockDwbc);
assertNotNull("BrightnessMappingStrategy should not be null", simple);
for (int i = 0; i < LUX_LEVELS.length; i++) {
assertEquals(DISPLAY_LEVELS[i], simple.getBrightness(LUX_LEVELS[i]),
@@ -216,7 +225,9 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(EMPTY_INT_ARRAY);
DisplayDeviceConfig ddc = createDdc(EMPTY_FLOAT_ARRAY, EMPTY_FLOAT_ARRAY, LUX_LEVELS,
EMPTY_FLOAT_ARRAY, DISPLAY_LEVELS);
- BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mMockDwbc);
assertNotNull("BrightnessMappingStrategy should not be null", simple);
for (int i = 1; i < LUX_LEVELS.length; i++) {
final float lux = (LUX_LEVELS[i - 1] + LUX_LEVELS[i]) / 2;
@@ -230,7 +241,8 @@ public class BrightnessMappingStrategyTest {
public void testSimpleStrategyIgnoresNewConfiguration() {
Resources res = createResources(DISPLAY_LEVELS_INT);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
final float[] lux = { 0f, 1f };
final float[] nits = { 0, PowerManager.BRIGHTNESS_ON };
@@ -245,7 +257,8 @@ public class BrightnessMappingStrategyTest {
public void testSimpleStrategyIgnoresNullConfiguration() {
Resources res = createResources(DISPLAY_LEVELS_INT);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
strategy.setBrightnessConfiguration(null);
final int n = DISPLAY_LEVELS_INT.length;
@@ -261,7 +274,8 @@ public class BrightnessMappingStrategyTest {
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS,
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT,
LUX_LEVELS, DISPLAY_LEVELS_NITS);
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
assertNotNull("BrightnessMappingStrategy should not be null", physical);
for (int i = 0; i < LUX_LEVELS.length; i++) {
final float expectedLevel = MathUtils.map(DISPLAY_RANGE_NITS[0], DISPLAY_RANGE_NITS[1],
@@ -279,7 +293,8 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(EMPTY_INT_ARRAY);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE,
LUX_LEVELS, DISPLAY_LEVELS_NITS);
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
assertNotNull("BrightnessMappingStrategy should not be null", physical);
Spline brightnessToNits =
Spline.createSpline(BACKLIGHT_RANGE_ZERO_TO_ONE, DISPLAY_RANGE_NITS);
@@ -297,7 +312,8 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(EMPTY_INT_ARRAY);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS,
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, LUX_LEVELS, DISPLAY_LEVELS_NITS);
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
final float[] lux = {0f, 1f};
final float[] nits = {
@@ -323,7 +339,8 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(EMPTY_INT_ARRAY);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS,
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, LUX_LEVELS, DISPLAY_LEVELS_NITS);
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
float[] adjustedNits50p = new float[DISPLAY_RANGE_NITS.length];
for (int i = 0; i < DISPLAY_RANGE_NITS.length; i++) {
adjustedNits50p[i] = DISPLAY_RANGE_NITS[i] * 0.5f;
@@ -367,7 +384,8 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(DISPLAY_LEVELS_INT);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS,
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, LUX_LEVELS, DISPLAY_LEVELS_NITS);
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
assertTrue(strategy instanceof BrightnessMappingStrategy.PhysicalMappingStrategy);
}
@@ -381,14 +399,16 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(EMPTY_INT_ARRAY);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS,
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, lux, DISPLAY_LEVELS_NITS);
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
assertNull(strategy);
// And make sure we get the same result even if it's monotone but not increasing.
lux[idx] = lux[idx + 1];
ddc = createDdc(DISPLAY_RANGE_NITS, DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, lux,
DISPLAY_LEVELS_NITS);
- strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ strategy = BrightnessMappingStrategy.create(res, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mMockDwbc);
assertNull(strategy);
}
@@ -402,11 +422,13 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(EMPTY_INT_ARRAY);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS,
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, lux, DISPLAY_LEVELS_NITS);
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
assertNull(strategy);
res = createResources(DISPLAY_LEVELS_INT);
- strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ strategy = BrightnessMappingStrategy.create(res, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mMockDwbc);
assertNull(strategy);
// Extra backlight level
@@ -416,7 +438,8 @@ public class BrightnessMappingStrategyTest {
res = createResources(backlight);
ddc = createDdc(DISPLAY_RANGE_NITS,
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, LUX_LEVELS, EMPTY_FLOAT_ARRAY);
- strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ strategy = BrightnessMappingStrategy.create(res, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mMockDwbc);
assertNull(strategy);
// Extra nits level
@@ -425,7 +448,8 @@ public class BrightnessMappingStrategyTest {
res = createResources(EMPTY_INT_ARRAY);
ddc = createDdc(DISPLAY_RANGE_NITS,
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, LUX_LEVELS, nits);
- strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ strategy = BrightnessMappingStrategy.create(res, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mMockDwbc);
assertNull(strategy);
}
@@ -433,15 +457,18 @@ public class BrightnessMappingStrategyTest {
public void testPhysicalStrategyRequiresNitsMapping() {
Resources res = createResources(EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/);
DisplayDeviceConfig ddc = createDdc(EMPTY_FLOAT_ARRAY /*nitsRange*/);
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
assertNull(physical);
res = createResources(EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/);
- physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ physical = BrightnessMappingStrategy.create(res, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mMockDwbc);
assertNull(physical);
res = createResources(EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/);
- physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
+ physical = BrightnessMappingStrategy.create(res, ddc, AUTO_BRIGHTNESS_MODE_DEFAULT,
+ mMockDwbc);
assertNull(physical);
}
@@ -450,10 +477,12 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE,
LUX_LEVELS, DISPLAY_LEVELS_NITS);
- assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc, mMockDwbc));
+ assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc));
ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
res = createResources(DISPLAY_LEVELS_INT);
- assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc, mMockDwbc));
+ assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc));
}
@Test
@@ -463,7 +492,8 @@ public class BrightnessMappingStrategyTest {
// Create an idle mode bms
// This will fail if it tries to fetch the wrong configuration.
- BrightnessMappingStrategy bms = BrightnessMappingStrategy.createForIdleMode(res, ddc,
+ BrightnessMappingStrategy bms = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_IDLE,
mMockDwbc);
assertNotNull("BrightnessMappingStrategy should not be null", bms);
@@ -652,7 +682,7 @@ public class BrightnessMappingStrategyTest {
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, GAMMA_CORRECTION_LUX,
GAMMA_CORRECTION_NITS);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
- mMockDwbc);
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
// Let's start with a validity check:
assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
@@ -683,7 +713,7 @@ public class BrightnessMappingStrategyTest {
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, GAMMA_CORRECTION_LUX,
GAMMA_CORRECTION_NITS);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
- mMockDwbc);
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
// Validity check:
assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
@@ -711,7 +741,7 @@ public class BrightnessMappingStrategyTest {
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, GAMMA_CORRECTION_LUX,
GAMMA_CORRECTION_NITS);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
- mMockDwbc);
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), /* delta= */ 0.0001f);
strategy.addUserDataPoint(/* lux= */ 2500, /* brightness= */ 1.0f);
assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), /* delta= */ 0.0001f);
@@ -735,7 +765,7 @@ public class BrightnessMappingStrategyTest {
DISPLAY_LEVELS_RANGE_BACKLIGHT_FLOAT, GAMMA_CORRECTION_LUX,
GAMMA_CORRECTION_NITS);
BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
- mMockDwbc);
+ AUTO_BRIGHTNESS_MODE_DEFAULT, mMockDwbc);
// Validity, as per tradition:
assertEquals(y0, strategy.getBrightness(x0), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
@@ -757,4 +787,14 @@ public class BrightnessMappingStrategyTest {
assertEquals(1.0f, strategy.getBrightness(x4), 0.0001f /* tolerance */);
assertEquals(adjustment, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
}
+
+ @Test
+ public void testGetMode() {
+ Resources res = createResourcesIdle(LUX_LEVELS_IDLE, DISPLAY_LEVELS_NITS_IDLE);
+ DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc,
+ AUTO_BRIGHTNESS_MODE_IDLE,
+ mMockDwbc);
+ assertEquals(AUTO_BRIGHTNESS_MODE_IDLE, strategy.getMode());
+ }
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
index acd9dceb16d5..02bd35a5b17f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -18,6 +18,7 @@ package com.android.server.display;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
@@ -28,7 +29,6 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
-import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -62,6 +62,7 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.testing.TestableContext;
import android.util.FloatProperty;
+import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
@@ -357,7 +358,7 @@ public final class DisplayPowerController2Test {
float followerBrightness = 0.4f;
float nits = 300;
when(mHolder.automaticBrightnessController.convertToNits(leadBrightness)).thenReturn(nits);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(followerBrightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(leadBrightness);
listener.onBrightnessChanged(leadBrightness);
@@ -372,7 +373,7 @@ public final class DisplayPowerController2Test {
float brightness = 0.6f;
nits = 600;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -404,7 +405,7 @@ public final class DisplayPowerController2Test {
float brightness = 0.3f;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(300f);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(anyFloat()))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(anyFloat()))
.thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -466,7 +467,7 @@ public final class DisplayPowerController2Test {
float brightness = 0.3f;
when(mHolder.automaticBrightnessController.convertToNits(anyFloat())).thenReturn(-1f);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(anyFloat()))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(anyFloat()))
.thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -500,7 +501,7 @@ public final class DisplayPowerController2Test {
when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness))
.thenReturn(nits);
when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(followerBrightness);
mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc);
@@ -534,7 +535,7 @@ public final class DisplayPowerController2Test {
when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness))
.thenReturn(nits);
when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(followerBrightness);
mHolder.dpc.updateBrightness();
@@ -592,9 +593,9 @@ public final class DisplayPowerController2Test {
float brightness = 0.6f;
float nits = 600;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
- when(secondFollowerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(secondFollowerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -625,9 +626,9 @@ public final class DisplayPowerController2Test {
brightness = 0.7f;
nits = 700;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
- when(secondFollowerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(secondFollowerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -697,9 +698,9 @@ public final class DisplayPowerController2Test {
float brightness = 0.6f;
float nits = 600;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(followerHolder.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerHolder.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
- when(secondFollowerHolder.automaticBrightnessController.convertToFloatScale(nits))
+ when(secondFollowerHolder.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -1124,7 +1125,7 @@ public final class DisplayPowerController2Test {
float newBrightness = 0.4f;
when(mHolder.brightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits);
- when(mHolder.automaticBrightnessController.convertToFloatScale(nits))
+ when(mHolder.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(newBrightness);
// New display device
setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class),
@@ -1141,12 +1142,9 @@ public final class DisplayPowerController2Test {
@Test
public void testShortTermModelPersistsWhenDisplayDeviceChanges() {
float lux = 2000;
- float brightness = 0.4f;
float nits = 500;
- when(mHolder.brightnessMappingStrategy.getUserLux()).thenReturn(lux);
- when(mHolder.brightnessMappingStrategy.getUserBrightness()).thenReturn(brightness);
- when(mHolder.brightnessMappingStrategy.convertToNits(brightness)).thenReturn(nits);
- when(mHolder.brightnessMappingStrategy.convertToFloatScale(nits)).thenReturn(brightness);
+ when(mHolder.automaticBrightnessController.getUserLux()).thenReturn(lux);
+ when(mHolder.automaticBrightnessController.getUserNits()).thenReturn(nits);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1);
@@ -1163,7 +1161,7 @@ public final class DisplayPowerController2Test {
any(Looper.class),
eq(mSensorManagerMock),
/* lightSensor= */ any(),
- eq(mHolder.brightnessMappingStrategy),
+ /* brightnessMappingStrategyMap= */ any(SparseArray.class),
/* lightSensorWarmUpTime= */ anyInt(),
/* brightnessMin= */ anyFloat(),
/* brightnessMax= */ anyFloat(),
@@ -1182,11 +1180,10 @@ public final class DisplayPowerController2Test {
eq(mContext),
any(BrightnessRangeController.class),
any(BrightnessThrottler.class),
- /* idleModeBrightnessMapper= */ isNull(),
/* ambientLightHorizonShort= */ anyInt(),
/* ambientLightHorizonLong= */ anyInt(),
eq(lux),
- eq(brightness)
+ eq(nits)
);
}
@@ -1219,7 +1216,7 @@ public final class DisplayPowerController2Test {
public void testDwbcCallsHappenOnHandler() {
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
- mHolder.dpc.setAutomaticScreenBrightnessMode(true);
+ mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
verify(mDisplayWhiteBalanceControllerMock, never()).setStrongModeEnabled(true);
// dispatch handler looper
@@ -1382,7 +1379,7 @@ public final class DisplayPowerController2Test {
BRIGHTNESS_RAMP_DECREASE_MAX);
// switch to idle mode
- mHolder.dpc.setAutomaticScreenBrightnessMode(/* idle= */ true);
+ mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
advanceTime(1);
// A second time, when switching to idle mode.
@@ -1411,7 +1408,7 @@ public final class DisplayPowerController2Test {
BRIGHTNESS_RAMP_DECREASE_MAX);
// switch to idle mode
- mHolder.dpc.setAutomaticScreenBrightnessMode(/* idle= */ true);
+ mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
advanceTime(1);
// A second time, when switching to idle mode.
@@ -1437,7 +1434,7 @@ public final class DisplayPowerController2Test {
mHolder.config, /* isEnabled= */ true);
// switch to idle mode
- mHolder.dpc.setAutomaticScreenBrightnessMode(true);
+ mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
// A second time when switching to idle mode.
verify(mHolder.animator, times(2)).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX,
@@ -1463,7 +1460,7 @@ public final class DisplayPowerController2Test {
mHolder.config, /* isEnabled= */ true);
// switch to idle mode
- mHolder.dpc.setAutomaticScreenBrightnessMode(true);
+ mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE,
BRIGHTNESS_RAMP_DECREASE_MAX_IDLE);
@@ -1839,7 +1836,7 @@ public final class DisplayPowerController2Test {
AutomaticBrightnessController getAutomaticBrightnessController(
AutomaticBrightnessController.Callbacks callbacks, Looper looper,
SensorManager sensorManager, Sensor lightSensor,
- BrightnessMappingStrategy interactiveModeBrightnessMapper,
+ SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap,
int lightSensorWarmUpTime, float brightnessMin, float brightnessMax,
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
@@ -1850,15 +1847,13 @@ public final class DisplayPowerController2Test {
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
BrightnessRangeController brightnessRangeController,
- BrightnessThrottler brightnessThrottler,
- BrightnessMappingStrategy idleModeBrightnessMapper,
- int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux,
- float userBrightness) {
+ BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
+ int ambientLightHorizonLong, float userLux, float userNits) {
return mAutomaticBrightnessController;
}
@Override
- BrightnessMappingStrategy getInteractiveModeBrightnessMapper(Resources resources,
+ BrightnessMappingStrategy getDefaultModeBrightnessMapper(Resources resources,
DisplayDeviceConfig displayDeviceConfig,
DisplayWhiteBalanceController displayWhiteBalanceController) {
return mBrightnessMappingStrategy;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index 50b0e167ef99..64cdac464720 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -18,6 +18,7 @@ package com.android.server.display;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_IDLE;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
@@ -28,7 +29,6 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
-import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
@@ -62,6 +62,7 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.testing.TestableContext;
import android.util.FloatProperty;
+import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayInfo;
@@ -357,7 +358,7 @@ public final class DisplayPowerControllerTest {
float followerBrightness = 0.4f;
float nits = 300;
when(mHolder.automaticBrightnessController.convertToNits(leadBrightness)).thenReturn(nits);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(followerBrightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(leadBrightness);
listener.onBrightnessChanged(leadBrightness);
@@ -375,7 +376,7 @@ public final class DisplayPowerControllerTest {
float brightness = 0.6f;
nits = 600;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -408,7 +409,7 @@ public final class DisplayPowerControllerTest {
float brightness = 0.3f;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(300f);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(anyFloat()))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(anyFloat()))
.thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -472,7 +473,7 @@ public final class DisplayPowerControllerTest {
float brightness = 0.3f;
when(mHolder.automaticBrightnessController.convertToNits(anyFloat())).thenReturn(-1f);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(anyFloat()))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(anyFloat()))
.thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -507,7 +508,7 @@ public final class DisplayPowerControllerTest {
when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness))
.thenReturn(nits);
when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(followerBrightness);
mHolder.dpc.addDisplayBrightnessFollower(followerDpc.dpc);
@@ -541,7 +542,7 @@ public final class DisplayPowerControllerTest {
when(mHolder.automaticBrightnessController.convertToNits(rawLeadBrightness))
.thenReturn(nits);
when(mHolder.automaticBrightnessController.getAmbientLux()).thenReturn(ambientLux);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(followerBrightness);
mHolder.dpc.updateBrightness();
@@ -600,9 +601,9 @@ public final class DisplayPowerControllerTest {
float brightness = 0.6f;
float nits = 600;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
- when(secondFollowerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(secondFollowerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -633,9 +634,9 @@ public final class DisplayPowerControllerTest {
brightness = 0.7f;
nits = 700;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(followerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
- when(secondFollowerDpc.automaticBrightnessController.convertToFloatScale(nits))
+ when(secondFollowerDpc.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -706,9 +707,9 @@ public final class DisplayPowerControllerTest {
float brightness = 0.6f;
float nits = 600;
when(mHolder.automaticBrightnessController.convertToNits(brightness)).thenReturn(nits);
- when(followerHolder.automaticBrightnessController.convertToFloatScale(nits))
+ when(followerHolder.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
- when(secondFollowerHolder.automaticBrightnessController.convertToFloatScale(nits))
+ when(secondFollowerHolder.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(brightness);
when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
listener.onBrightnessChanged(brightness);
@@ -1056,7 +1057,7 @@ public final class DisplayPowerControllerTest {
float newBrightness = 0.4f;
when(mHolder.brightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits);
- when(mHolder.automaticBrightnessController.convertToFloatScale(nits))
+ when(mHolder.automaticBrightnessController.getBrightnessFromNits(nits))
.thenReturn(newBrightness);
// New display device
setUpDisplay(DISPLAY_ID, "new_unique_id", mHolder.display, mock(DisplayDevice.class),
@@ -1073,12 +1074,9 @@ public final class DisplayPowerControllerTest {
@Test
public void testShortTermModelPersistsWhenDisplayDeviceChanges() {
float lux = 2000;
- float brightness = 0.4f;
float nits = 500;
- when(mHolder.brightnessMappingStrategy.getUserLux()).thenReturn(lux);
- when(mHolder.brightnessMappingStrategy.getUserBrightness()).thenReturn(brightness);
- when(mHolder.brightnessMappingStrategy.convertToNits(brightness)).thenReturn(nits);
- when(mHolder.brightnessMappingStrategy.convertToFloatScale(nits)).thenReturn(brightness);
+ when(mHolder.automaticBrightnessController.getUserLux()).thenReturn(lux);
+ when(mHolder.automaticBrightnessController.getUserNits()).thenReturn(nits);
DisplayPowerRequest dpr = new DisplayPowerRequest();
mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
advanceTime(1);
@@ -1095,7 +1093,7 @@ public final class DisplayPowerControllerTest {
any(Looper.class),
eq(mSensorManagerMock),
/* lightSensor= */ any(),
- eq(mHolder.brightnessMappingStrategy),
+ /* brightnessMappingStrategyMap= */ any(SparseArray.class),
/* lightSensorWarmUpTime= */ anyInt(),
/* brightnessMin= */ anyFloat(),
/* brightnessMax= */ anyFloat(),
@@ -1114,11 +1112,10 @@ public final class DisplayPowerControllerTest {
eq(mContext),
any(BrightnessRangeController.class),
any(BrightnessThrottler.class),
- /* idleModeBrightnessMapper= */ isNull(),
/* ambientLightHorizonShort= */ anyInt(),
/* ambientLightHorizonLong= */ anyInt(),
eq(lux),
- eq(brightness)
+ eq(nits)
);
}
@@ -1151,7 +1148,7 @@ public final class DisplayPowerControllerTest {
public void testDwbcCallsHappenOnHandler() {
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
- mHolder.dpc.setAutomaticScreenBrightnessMode(true);
+ mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
verify(mDisplayWhiteBalanceControllerMock, never()).setStrongModeEnabled(true);
// dispatch handler looper
@@ -1293,7 +1290,7 @@ public final class DisplayPowerControllerTest {
BRIGHTNESS_RAMP_DECREASE_MAX);
// switch to idle
- mHolder.dpc.setAutomaticScreenBrightnessMode(/* idle= */ true);
+ mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
advanceTime(1);
verify(mHolder.animator, times(2)).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX,
@@ -1320,7 +1317,7 @@ public final class DisplayPowerControllerTest {
BRIGHTNESS_RAMP_DECREASE_MAX);
// switch to idle
- mHolder.dpc.setAutomaticScreenBrightnessMode(/* idle= */ true);
+ mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
advanceTime(1);
verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE,
@@ -1347,7 +1344,7 @@ public final class DisplayPowerControllerTest {
mHolder.config, /* isEnabled= */ true);
// switch to idle mode
- mHolder.dpc.setAutomaticScreenBrightnessMode(true);
+ mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
// second time when switching to idle screen brightness mode
verify(mHolder.animator, times(2)).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX,
@@ -1372,7 +1369,7 @@ public final class DisplayPowerControllerTest {
mHolder.config, /* isEnabled= */ true);
// switch to idle mode
- mHolder.dpc.setAutomaticScreenBrightnessMode(true);
+ mHolder.dpc.setAutomaticScreenBrightnessMode(AUTO_BRIGHTNESS_MODE_IDLE);
verify(mHolder.animator).setAnimationTimeLimits(BRIGHTNESS_RAMP_INCREASE_MAX_IDLE,
BRIGHTNESS_RAMP_DECREASE_MAX_IDLE);
@@ -1655,7 +1652,7 @@ public final class DisplayPowerControllerTest {
AutomaticBrightnessController getAutomaticBrightnessController(
AutomaticBrightnessController.Callbacks callbacks, Looper looper,
SensorManager sensorManager, Sensor lightSensor,
- BrightnessMappingStrategy interactiveModeBrightnessMapper,
+ SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap,
int lightSensorWarmUpTime, float brightnessMin, float brightnessMax,
float dozeScaleFactor, int lightSensorRate, int initialLightSensorRate,
long brighteningLightDebounceConfig, long darkeningLightDebounceConfig,
@@ -1666,15 +1663,13 @@ public final class DisplayPowerControllerTest {
HysteresisLevels ambientBrightnessThresholdsIdle,
HysteresisLevels screenBrightnessThresholdsIdle, Context context,
BrightnessRangeController brightnessRangeController,
- BrightnessThrottler brightnessThrottler,
- BrightnessMappingStrategy idleModeBrightnessMapper,
- int ambientLightHorizonShort, int ambientLightHorizonLong, float userLux,
- float userBrightness) {
+ BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
+ int ambientLightHorizonLong, float userLux, float userNits) {
return mAutomaticBrightnessController;
}
@Override
- BrightnessMappingStrategy getInteractiveModeBrightnessMapper(Resources resources,
+ BrightnessMappingStrategy getDefaultModeBrightnessMapper(Resources resources,
DisplayDeviceConfig displayDeviceConfig,
DisplayWhiteBalanceController displayWhiteBalanceController) {
return mBrightnessMappingStrategy;
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
index 52fa91f5fe0e..2d0c3fdb6352 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
@@ -293,21 +293,21 @@ public final class DisplayBrightnessControllerTest {
}
@Test
- public void testConvertToFloatScale() {
+ public void testGetBrightnessFromNits() {
float brightness = 0.5f;
float nits = 300;
// ABC is null
assertEquals(PowerManager.BRIGHTNESS_INVALID_FLOAT,
- mDisplayBrightnessController.convertToFloatScale(nits), /* delta= */ 0);
+ mDisplayBrightnessController.getBrightnessFromNits(nits), /* delta= */ 0);
AutomaticBrightnessController automaticBrightnessController =
mock(AutomaticBrightnessController.class);
- when(automaticBrightnessController.convertToFloatScale(nits)).thenReturn(brightness);
+ when(automaticBrightnessController.getBrightnessFromNits(nits)).thenReturn(brightness);
mDisplayBrightnessController.setAutomaticBrightnessController(
automaticBrightnessController);
- assertEquals(brightness, mDisplayBrightnessController.convertToFloatScale(nits),
+ assertEquals(brightness, mDisplayBrightnessController.getBrightnessFromNits(nits),
/* delta= */ 0);
}
@@ -329,7 +329,7 @@ public final class DisplayBrightnessControllerTest {
float brightness = 0.3f;
AutomaticBrightnessController automaticBrightnessController =
mock(AutomaticBrightnessController.class);
- when(automaticBrightnessController.convertToFloatScale(nits)).thenReturn(brightness);
+ when(automaticBrightnessController.getBrightnessFromNits(nits)).thenReturn(brightness);
when(mBrightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits);
mDisplayBrightnessController.setAutomaticBrightnessController(
automaticBrightnessController);
@@ -340,7 +340,7 @@ public final class DisplayBrightnessControllerTest {
// When the nits value is invalid, the brightness is resumed from where it was last set
nits = -1;
brightness = 0.4f;
- when(automaticBrightnessController.convertToFloatScale(nits)).thenReturn(brightness);
+ when(automaticBrightnessController.getBrightnessFromNits(nits)).thenReturn(brightness);
when(mBrightnessSetting.getBrightnessNitsForDefaultDisplay()).thenReturn(nits);
when(mBrightnessSetting.getBrightness()).thenReturn(brightness);
mDisplayBrightnessController.setAutomaticBrightnessController(
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
index b3605ccfc25d..caa08647628e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
@@ -221,6 +221,7 @@ public class AsyncProcessStartTest {
r.setStartUid(myUid());
r.setHostingRecord(new HostingRecord(HostingRecord.HOSTING_TYPE_BROADCAST));
r.makeActive(thread, mAms.mProcessStats);
+ ProcessRecord.updateProcessRecordNodes(r);
doNothing().when(r).killLocked(any(), any(), anyInt(), anyInt(), anyBoolean(),
anyBoolean());
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index e4da2b673efa..cc6fc80d9fa1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -1756,6 +1756,7 @@ public final class BroadcastQueueModernImplTest extends BaseBroadcastQueueTest {
private ProcessRecord makeProcessRecord(ApplicationInfo info) {
final ProcessRecord r = spy(new ProcessRecord(mAms, info, info.processName, info.uid));
r.setPid(mNextPid.incrementAndGet());
+ ProcessRecord.updateProcessRecordNodes(r);
return r;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 0fd424b89837..115a5b0d53f2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -336,6 +336,7 @@ public class BroadcastQueueTest extends BaseBroadcastQueueTest {
final ProcessRecord r = spy(new ProcessRecord(mAms, ai, processName, ai.uid));
r.mState = spy(r.mState);
r.setPid(mNextPid.getAndIncrement());
+ ProcessRecord.updateProcessRecordNodes(r);
mActiveProcesses.add(r);
final IApplicationThread thread;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index f45dd391fbc7..f386c3bf6a15 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -114,7 +114,9 @@ import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -258,25 +260,40 @@ public class MockingOomAdjusterTests {
ArrayList<ProcessRecord> lru = sService.mProcessList.getLruProcessesLOSP();
lru.clear();
Collections.addAll(lru, apps);
- for (ProcessRecord app : apps) {
- sService.mOomAdjuster.onProcessBeginLocked(app);
- }
}
/**
* Run updateOomAdjLocked().
+ * - If there is no process specified, run updateOomAdjLocked(int) on existing lru
* - If there's only one process, then it calls updateOomAdjLocked(ProcessRecord, int).
* - Otherwise, sets the processes to the LRU and run updateOomAdjLocked(int).
*/
@SuppressWarnings("GuardedBy")
private void updateOomAdj(ProcessRecord... apps) {
- if (apps.length == 1) {
- sService.mOomAdjuster.onProcessBeginLocked(apps[0]);
- sService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE);
- } else {
- setProcessesToLru(apps);
+ if (apps.length == 0) {
+ updateProcessRecordNodes(sService.mProcessList.getLruProcessesLOSP());
sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
- sService.mProcessList.getLruProcessesLOSP().clear();
+ } else {
+ updateProcessRecordNodes(Arrays.asList(apps));
+ if (apps.length == 1) {
+ sService.mOomAdjuster.updateOomAdjLocked(apps[0], OOM_ADJ_REASON_NONE);
+ } else {
+ setProcessesToLru(apps);
+ sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ sService.mProcessList.getLruProcessesLOSP().clear();
+ }
+ }
+ }
+
+ /**
+ * Fix up the pointers in the {@link ProcessRecordNode#mApp}:
+ * because we used the mokito spy objects all over the tests here, but the internal
+ * pointers in the {@link ProcessRecordNode#mApp} actually point to the real object.
+ * This needs to be fixed up here.
+ */
+ private void updateProcessRecordNodes(List<ProcessRecord> apps) {
+ for (ProcessRecord app : apps) {
+ ProcessRecord.updateProcessRecordNodes(app);
}
}
@@ -613,7 +630,6 @@ public class MockingOomAdjusterTests {
s.lastTopAlmostPerceptibleBindRequestUptimeMs = nowUptime;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- sService.mOomAdjuster.onProcessBeginLocked(system);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -636,7 +652,6 @@ public class MockingOomAdjusterTests {
s.lastTopAlmostPerceptibleBindRequestUptimeMs =
nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- sService.mOomAdjuster.onProcessBeginLocked(system);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -660,7 +675,6 @@ public class MockingOomAdjusterTests {
nowUptime - 2 * sService.mConstants.mServiceBindAlmostPerceptibleTimeoutMs;
s.getConnections().clear();
app.mServices.updateHasTopStartedAlmostPerceptibleServices();
- sService.mOomAdjuster.onProcessBeginLocked(system);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
updateOomAdj(app);
@@ -679,7 +693,6 @@ public class MockingOomAdjusterTests {
MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, true));
system.mState.setMaxAdj(PERSISTENT_PROC_ADJ);
system.mState.setHasTopUi(true);
- sService.mOomAdjuster.onProcessBeginLocked(system);
// Simulate the system starting and binding to a service in the app.
ServiceRecord s = bindService(app, system,
null, Context.BIND_ALMOST_PERCEPTIBLE, mock(IBinder.class));
@@ -1532,7 +1545,7 @@ public class MockingOomAdjusterTests {
client2.mServices.setHasForegroundServices(false, 0, /* hasNoneType=*/false);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(client2, OOM_ADJ_REASON_NONE);
+ updateOomAdj(client2);
assertEquals(PROCESS_STATE_CACHED_EMPTY, client2.mState.getSetProcState());
assertEquals(PROCESS_STATE_CACHED_EMPTY, client.mState.getSetProcState());
@@ -2018,7 +2031,6 @@ public class MockingOomAdjusterTests {
app.setPendingFinishAttach(true);
app.mState.setHasForegroundActivities(false);
- sService.mOomAdjuster.onProcessBeginLocked(app);
sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
@@ -2035,7 +2047,6 @@ public class MockingOomAdjusterTests {
app.mState.setHasForegroundActivities(true);
doReturn(app).when(sService).getTopApp();
- sService.mOomAdjuster.onProcessBeginLocked(app);
sService.mOomAdjuster.setAttachingProcessStatesLSP(app);
updateOomAdj(app);
@@ -2106,7 +2117,7 @@ public class MockingOomAdjusterTests {
setServiceMap(s3, MOCKAPP5_UID, cn3);
setServiceMap(c2s, MOCKAPP3_UID, cn4);
app2UidRecord.setIdle(false);
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ updateOomAdj();
assertProcStates(app1, PROCESS_STATE_FOREGROUND_SERVICE, PERCEPTIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
@@ -2470,8 +2481,6 @@ public class MockingOomAdjusterTests {
lru.clear();
lru.add(app2);
lru.add(app);
- sService.mOomAdjuster.onProcessBeginLocked(app2);
- sService.mOomAdjuster.onProcessBeginLocked(app);
final ComponentName cn = ComponentName.unflattenFromString(
MOCKAPP_PACKAGENAME + "/.TestService");
@@ -2506,7 +2515,7 @@ public class MockingOomAdjusterTests {
app2.mState.setHasShownUi(false);
sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ updateOomAdj();
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-ui-services");
assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj2, "cch-started-services");
@@ -2515,7 +2524,7 @@ public class MockingOomAdjusterTests {
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
app.mState.setHasShownUi(false);
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ updateOomAdj();
assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
@@ -2524,7 +2533,7 @@ public class MockingOomAdjusterTests {
app.mState.setAdjType(null);
app.mState.setSetAdj(UNKNOWN_ADJ);
s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ updateOomAdj();
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
@@ -2542,7 +2551,7 @@ public class MockingOomAdjusterTests {
s.lastActivity = now;
app.mServices.startService(s);
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ updateOomAdj();
assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
@@ -2553,7 +2562,7 @@ public class MockingOomAdjusterTests {
app.mState.setSetAdj(UNKNOWN_ADJ);
app.mState.setHasShownUi(false);
s.lastActivity = now - sService.mConstants.MAX_SERVICE_INACTIVITY - 1;
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ updateOomAdj();
assertProcStates(app, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
assertProcStates(app2, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
@@ -2561,7 +2570,7 @@ public class MockingOomAdjusterTests {
doReturn(userOther).when(sService.mUserController).getCurrentUserId();
sService.mOomAdjuster.handleUserSwitchedLocked();
- sService.mOomAdjuster.updateOomAdjLocked(OOM_ADJ_REASON_NONE);
+ updateOomAdj();
assertProcStates(app, true, PROCESS_STATE_SERVICE, cachedAdj1, "cch-started-services");
assertProcStates(app2, false, PROCESS_STATE_SERVICE, SERVICE_ADJ, "started-services");
}
@@ -2584,7 +2593,7 @@ public class MockingOomAdjusterTests {
app.mServices.updateHasAboveClientLocked();
assertFalse(app.mServices.hasAboveClient());
- sService.mOomAdjuster.updateOomAdjLocked(app, OOM_ADJ_REASON_NONE);
+ updateOomAdj(app);
assertEquals(FOREGROUND_APP_ADJ, app.mState.getSetAdj());
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
index 7444403f88c8..ae53e707a7cc 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/SuspendPackageHelperTest.kt
@@ -19,7 +19,6 @@ package com.android.server.pm
import android.app.AppOpsManager
import android.content.Intent
import android.content.pm.SuspendDialogInfo
-import android.content.pm.UserPackage
import android.os.Binder
import android.os.PersistableBundle
import com.android.server.testutils.any
@@ -42,18 +41,12 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
.thenReturn(AppOpsManager.MODE_DEFAULT)
}
- companion object {
- val doUserPackage = UserPackage.of(TEST_USER_ID, DEVICE_OWNER_PACKAGE)
- val platformUserPackage = UserPackage.of(TEST_USER_ID, PLATFORM_PACKAGE_NAME)
- val testUserPackage1 = UserPackage.of(TEST_USER_ID, TEST_PACKAGE_1)
- }
-
@Test
fun setPackagesSuspended() {
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
+ null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
@@ -70,14 +63,14 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_emptyPackageName() {
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
null /* packageNames */, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
+ null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).isNull()
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOfNulls(0), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
+ null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).isEmpty()
@@ -87,8 +80,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_callerIsNotAllowed() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */,
- testUserPackage1, TEST_USER_ID,
+ null /* launcherExtras */, null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID,
Binder.getCallingUid(), false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -99,7 +91,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_callerSuspendItself() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(DEVICE_OWNER_PACKAGE), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
+ null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -110,7 +102,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun setPackagesSuspended_nonexistentPackage() {
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(NONEXISTENT_PACKAGE), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
+ null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
assertThat(failedNames).asList().hasSize(1)
@@ -123,7 +115,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
INSTALLER_PACKAGE, UNINSTALLER_PACKAGE, VERIFIER_PACKAGE, PERMISSION_CONTROLLER_PACKAGE)
val failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
knownPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
+ null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)!!
assertThat(failedNames.size).isEqualTo(knownPackages.size)
@@ -137,14 +129,14 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
+ null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
Mockito.clearInvocations(broadcastHelper)
assertThat(failedNames).isEmpty()
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, false /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
+ null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
@@ -192,7 +184,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
appExtras.putString(TEST_PACKAGE_1, TEST_PACKAGE_1)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, appExtras, null /* launcherExtras */,
- null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -210,22 +202,22 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
val targetPackages = arrayOf(TEST_PACKAGE_1, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, appExtras, null /* launcherExtras */,
- null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
Mockito.clearInvocations(broadcastHelper)
assertThat(failedNames).isEmpty()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
+ TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
assertThat(SuspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid)).isNotNull()
assertThat(SuspendPackageHelper.getSuspendedPackageAppExtras(pms.snapshotComputer(),
TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isNotNull()
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspender -> suspender.packageName == DEVICE_OWNER_PACKAGE },
+ targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE },
TEST_USER_ID)
testHandler.flush()
@@ -251,7 +243,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -266,7 +258,7 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
fun isPackageSuspended() {
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, null /* dialogInfo */, doUserPackage,
+ null /* launcherExtras */, null /* dialogInfo */, DEVICE_OWNER_PACKAGE,
TEST_USER_ID, deviceOwnerUid, false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
@@ -281,13 +273,13 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
launcherExtras.putString(TEST_PACKAGE_2, TEST_PACKAGE_2)
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_2), true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
}
@Test
@@ -298,57 +290,57 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
// Suspend.
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, doUserPackage, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
assertThat(failedNames).isEmpty()
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
// Suspend by system.
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, platformUserPackage, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, PLATFORM_PACKAGE_NAME, TEST_USER_ID, deviceOwnerUid,
false /* quarantined */)
assertThat(failedNames).isEmpty()
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(platformUserPackage)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(PLATFORM_PACKAGE_NAME)
// QAS by package1.
failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
targetPackages, true /* suspended */, null /* appExtras */, launcherExtras,
- null /* dialogInfo */, testUserPackage1, TEST_USER_ID, deviceOwnerUid,
+ null /* dialogInfo */, TEST_PACKAGE_1, TEST_USER_ID, deviceOwnerUid,
true /* quarantined */)
assertThat(failedNames).isEmpty()
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(testUserPackage1)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(TEST_PACKAGE_1)
// Un-QAS by package1.
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == testUserPackage1 },
+ targetPackages, { suspendingPackage -> suspendingPackage == TEST_PACKAGE_1 },
TEST_USER_ID)
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(platformUserPackage)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(PLATFORM_PACKAGE_NAME)
// Un-suspend by system.
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspender -> suspender.packageName == PLATFORM_PACKAGE_NAME },
+ targetPackages, { suspendingPackage -> suspendingPackage == PLATFORM_PACKAGE_NAME },
TEST_USER_ID)
testHandler.flush()
assertThat(suspendPackageHelper.getSuspendingPackage(pms.snapshotComputer(),
- TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(doUserPackage)
+ TEST_PACKAGE_2, TEST_USER_ID, deviceOwnerUid)).isEqualTo(DEVICE_OWNER_PACKAGE)
// Unsuspend.
suspendPackageHelper.removeSuspensionsBySuspendingPackage(pms.snapshotComputer(),
- targetPackages, { suspendingPackage -> suspendingPackage == doUserPackage },
+ targetPackages, { suspendingPackage -> suspendingPackage == DEVICE_OWNER_PACKAGE },
TEST_USER_ID)
testHandler.flush()
@@ -362,13 +354,13 @@ class SuspendPackageHelperTest : PackageHelperTestBase() {
.setTitle(TEST_PACKAGE_1).build()
var failedNames = suspendPackageHelper.setPackagesSuspended(pms.snapshotComputer(),
arrayOf(TEST_PACKAGE_1), true /* suspended */, null /* appExtras */,
- null /* launcherExtras */, dialogInfo, doUserPackage, TEST_USER_ID,
+ null /* launcherExtras */, dialogInfo, DEVICE_OWNER_PACKAGE, TEST_USER_ID,
deviceOwnerUid, false /* quarantined */)
testHandler.flush()
assertThat(failedNames).isEmpty()
val result = suspendPackageHelper.getSuspendedDialogInfo(pms.snapshotComputer(),
- TEST_PACKAGE_1, doUserPackage, TEST_USER_ID, deviceOwnerUid)!!
+ TEST_PACKAGE_1, DEVICE_OWNER_PACKAGE, TEST_USER_ID, deviceOwnerUid)!!
assertThat(result.title).isEqualTo(TEST_PACKAGE_1)
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index b2854ceb1017..ef15f60101d4 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -868,6 +868,7 @@ public class CompatConfigTest {
+ "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />"
+ "<compat-change id=\"1235\" name=\"MY_CHANGE2\" disabled=\"true\" />"
+ "<compat-change id=\"1236\" name=\"MY_CHANGE3\" />"
+ + "<compat-change id=\"1237\" name=\"MY_CHANGE4\" enableSinceTargetSdk=\"31\" />"
+ "</config>";
File dir = createTempDir();
@@ -885,32 +886,12 @@ public class CompatConfigTest {
ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
assertThat(compatConfig.isChangeEnabled(1236L,
ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
- }
-
- @Test
- public void testReadApexConfig() throws IOException {
- String configXml = "<config>"
- + "<compat-change id=\"1234\" name=\"MY_CHANGE1\" enableAfterTargetSdk=\"2\" />"
- + "<compat-change id=\"1235\" name=\"MY_CHANGE2\" disabled=\"true\" />"
- + "<compat-change id=\"1236\" name=\"MY_CHANGE3\" />"
- + "<compat-change id=\"1237\" name=\"MY_CHANGE4\" enableSinceTargetSdk=\"31\" />"
- + "</config>";
-
- File dir = createTempDir();
- writeToFile(dir, "platform_compat_config.xml", configXml);
- CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
- compatConfig.forceNonDebuggableFinalForTest(false);
+ assertThat(compatConfig.isChangeEnabled(1237L,
+ ApplicationInfoBuilder.create().withTargetSdk(31).build())).isFalse();
- compatConfig.initConfigFromLib(dir);
+ // Force the platform sdk version to be same as enabled target sdk
+ when(mBuildClassifier.platformTargetSdk()).thenReturn(31);
- assertThat(compatConfig.isChangeEnabled(1234L,
- ApplicationInfoBuilder.create().withTargetSdk(1).build())).isFalse();
- assertThat(compatConfig.isChangeEnabled(1234L,
- ApplicationInfoBuilder.create().withTargetSdk(3).build())).isTrue();
- assertThat(compatConfig.isChangeEnabled(1235L,
- ApplicationInfoBuilder.create().withTargetSdk(5).build())).isFalse();
- assertThat(compatConfig.isChangeEnabled(1236L,
- ApplicationInfoBuilder.create().withTargetSdk(1).build())).isTrue();
assertThat(compatConfig.isChangeEnabled(1237L,
ApplicationInfoBuilder.create().withTargetSdk(31).build())).isTrue();
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
index 1dd64ffa5dde..943a9c4759c4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -18,6 +18,7 @@ package com.android.server.devicepolicy;
import static android.os.UserHandle.USER_SYSTEM;
import static com.android.server.devicepolicy.DpmTestUtils.writeInputStreamToFile;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -221,21 +222,21 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.R);
// Pretend some packages are suspended.
- when(getServices().packageManagerInternal.isAdminSuspendingAnyPackages(
- USER_SYSTEM)).thenReturn(true);
+ when(getServices().packageManagerInternal.isSuspendingAnyPackages(
+ PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
verify(getServices().packageManagerInternal, never())
- .unsuspendAdminSuspendedPackages(USER_SYSTEM);
+ .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
sendBroadcastWithUser(dpms, Intent.ACTION_USER_STARTED, USER_SYSTEM);
// Verify that actual package suspension state is not modified after user start
verify(getServices().packageManagerInternal, never())
- .unsuspendAdminSuspendedPackages(USER_SYSTEM);
+ .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
- any(), anyBoolean(), any(), any(), any(), anyInt(), any(), anyInt(), anyInt());
+ any(), anyBoolean(), any(), any(), any(), anyInt(), any(), anyInt());
final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
@@ -254,14 +255,14 @@ public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
prepareAdmin1AsPo(COPE_PROFILE_USER_ID, Build.VERSION_CODES.Q);
// Pretend some packages are suspended.
- when(getServices().packageManagerInternal.isAdminSuspendingAnyPackages(
- USER_SYSTEM)).thenReturn(true);
+ when(getServices().packageManagerInternal.isSuspendingAnyPackages(
+ PLATFORM_PACKAGE_NAME, USER_SYSTEM)).thenReturn(true);
final DevicePolicyManagerServiceTestable dpms = bootDpmsUp();
// Verify that apps get unsuspended.
verify(getServices().packageManagerInternal)
- .unsuspendAdminSuspendedPackages(USER_SYSTEM);
+ .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, USER_SYSTEM);
final DpmMockContext poContext = new DpmMockContext(getServices(), mRealTestContext);
poContext.binder.callingUid = UserHandle.getUid(COPE_PROFILE_USER_ID, COPE_ADMIN1_APP_ID);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 24704034ae0c..f4dac2c10d0f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -63,6 +63,7 @@ import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_PROFILE_OFF_DEADLINE;
import static com.android.server.devicepolicy.DevicePolicyManagerService.ACTION_TURN_PROFILE_ON_NOTIFICATION;
import static com.android.server.devicepolicy.DpmMockContext.CALLER_USER_HANDLE;
+import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
import static com.android.server.testutils.TestUtils.assertExpectException;
import static com.google.common.truth.Truth.assertThat;
@@ -5079,7 +5080,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
verify(getServices().iwindowManager).refreshScreenCaptureDisabled();
// Unsuspend personal apps
verify(getServices().packageManagerInternal)
- .unsuspendAdminSuspendedPackages(UserHandle.USER_SYSTEM);
+ .unsuspendForSuspendingPackage(PLATFORM_PACKAGE_NAME, UserHandle.USER_SYSTEM);
verify(getServices().subscriptionManager).setSubscriptionUserHandle(0, null);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
FLAG_ENABLE_WORK_PROFILE_TELEPHONY, "false", false);
@@ -7534,7 +7535,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
.cancel(eq(SystemMessageProto.SystemMessage.NOTE_PERSONAL_APPS_SUSPENDED));
// Verify that the apps are NOT unsuspeded.
verify(getServices().ipackageManager, never()).setPackagesSuspendedAsUser(
- any(), eq(false), any(), any(), any(), anyInt(), any(), anyInt(), anyInt());
+ any(), eq(false), any(), any(), any(), anyInt(), any(), anyInt());
// Verify that DPC is invoked to check policy compliance.
verify(mContext.spiedContext).startActivityAsUser(
MockUtils.checkIntentAction(ACTION_CHECK_POLICY_COMPLIANCE),
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 708ee352a8c9..99fa30c588db 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -1706,6 +1706,15 @@ public class HdmiControlServiceTest {
verify(mHdmiControlServiceSpy, times(1)).startArcAction(eq(false), any());
}
+ @Test
+ public void onHotplugIn_invalidPortId_noAddressAllocation() {
+ mHdmiControlServiceSpy.onHotplug(-1, true);
+ mTestLooper.dispatchAll();
+
+ verify(mHdmiControlServiceSpy, times(0))
+ .allocateLogicalAddress(any(), eq(INITIATED_BY_HOTPLUG));
+ }
+
protected static class MockPlaybackDevice extends HdmiCecLocalDevicePlayback {
private boolean mCanGoToStandby;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 48c00a86fd17..56c75b52cf18 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -75,6 +75,7 @@ import static android.os.UserHandle.USER_SYSTEM;
import static android.os.UserManager.USER_TYPE_FULL_SECONDARY;
import static android.os.UserManager.USER_TYPE_PROFILE_CLONE;
import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED;
+import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
import static android.service.notification.Adjustment.KEY_IMPORTANCE;
import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
@@ -474,7 +475,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker;
TestableFlagResolver mTestFlagResolver = new TestableFlagResolver();
- @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
1 << 30);
@Mock
@@ -640,6 +641,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
});
// TODO (b/291907312): remove feature flag
+ // NOTE: Prefer using the @EnableFlag annotation where possible. Do not add any android.app
+ // flags here.
mSetFlagsRule.disableFlags(Flags.FLAG_REFACTOR_ATTENTION_HELPER,
Flags.FLAG_POLITE_NOTIFICATIONS);
initNMS();
@@ -6316,15 +6319,22 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(visitor, times(1)).accept(eq(personIcon3.getUri()));
}
+ private PendingIntent getPendingIntentWithUri(Uri uri) {
+ return PendingIntent.getActivity(mContext, 0,
+ new Intent("action", uri),
+ PendingIntent.FLAG_IMMUTABLE);
+ }
+
@Test
- public void testVisitUris_callStyle() {
+ @EnableFlags({android.app.Flags.FLAG_VISIT_RISKY_URIS})
+ public void testVisitUris_callStyle_ongoingCall() {
Icon personIcon = Icon.createWithContentUri("content://media/person");
Icon verificationIcon = Icon.createWithContentUri("content://media/verification");
Person callingPerson = new Person.Builder().setName("Someone")
.setIcon(personIcon)
.build();
- PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
- PendingIntent.FLAG_IMMUTABLE);
+ Uri hangUpUri = Uri.parse("content://intent/hangup");
+ PendingIntent hangUpIntent = getPendingIntentWithUri(hangUpUri);
Notification n = new Notification.Builder(mContext, "a")
.setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent)
.setVerificationIcon(verificationIcon))
@@ -6337,6 +6347,36 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(visitor, times(1)).accept(eq(personIcon.getUri()));
verify(visitor, times(1)).accept(eq(verificationIcon.getUri()));
+ verify(visitor, times(1)).accept(eq(hangUpUri));
+ }
+
+ @Test
+ @EnableFlags({android.app.Flags.FLAG_VISIT_RISKY_URIS})
+ public void testVisitUris_callStyle_incomingCall() {
+ Icon personIcon = Icon.createWithContentUri("content://media/person");
+ Icon verificationIcon = Icon.createWithContentUri("content://media/verification");
+ Person callingPerson = new Person.Builder().setName("Someone")
+ .setIcon(personIcon)
+ .build();
+ Uri answerUri = Uri.parse("content://intent/answer");
+ PendingIntent answerIntent = getPendingIntentWithUri(answerUri);
+ Uri declineUri = Uri.parse("content://intent/decline");
+ PendingIntent declineIntent = getPendingIntentWithUri(declineUri);
+ Notification n = new Notification.Builder(mContext, "a")
+ .setStyle(Notification.CallStyle.forIncomingCall(callingPerson, declineIntent,
+ answerIntent)
+ .setVerificationIcon(verificationIcon))
+ .setContentTitle("Calling...")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .build();
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ n.visitUris(visitor);
+
+ verify(visitor, times(1)).accept(eq(personIcon.getUri()));
+ verify(visitor, times(1)).accept(eq(verificationIcon.getUri()));
+ verify(visitor, times(1)).accept(eq(answerIntent.getIntent().getData()));
+ verify(visitor, times(1)).accept(eq(declineUri));
}
@Test
@@ -6385,23 +6425,80 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ @EnableFlags({android.app.Flags.FLAG_VISIT_RISKY_URIS})
public void testVisitUris_wearableExtender() {
Icon actionIcon = Icon.createWithContentUri("content://media/action");
Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction");
- PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(),
- PendingIntent.FLAG_IMMUTABLE);
+ Uri displayIntentUri = Uri.parse("content://intent/display");
+ PendingIntent displayIntent = getPendingIntentWithUri(displayIntentUri);
+ Uri actionIntentUri = Uri.parse("content://intent/action");
+ PendingIntent actionIntent = getPendingIntentWithUri(actionIntentUri);
+ Uri wearActionIntentUri = Uri.parse("content://intent/wear");
+ PendingIntent wearActionIntent = getPendingIntentWithUri(wearActionIntentUri);
Notification n = new Notification.Builder(mContext, "a")
.setSmallIcon(android.R.drawable.sym_def_app_icon)
- .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build())
- .extend(new Notification.WearableExtender().addAction(
- new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build()))
+ .addAction(
+ new Notification.Action.Builder(actionIcon, "Hey!", actionIntent).build())
+ .extend(new Notification.WearableExtender()
+ .setDisplayIntent(displayIntent)
+ .addAction(new Notification.Action.Builder(wearActionIcon, "Wear!",
+ wearActionIntent)
+ .build()))
.build();
Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
n.visitUris(visitor);
verify(visitor).accept(eq(actionIcon.getUri()));
+ verify(visitor, times(1)).accept(eq(actionIntentUri));
verify(visitor).accept(eq(wearActionIcon.getUri()));
+ verify(visitor, times(1)).accept(eq(wearActionIntentUri));
+ }
+
+ @Test
+ @EnableFlags({android.app.Flags.FLAG_VISIT_RISKY_URIS})
+ public void testVisitUris_tvExtender() {
+ Uri contentIntentUri = Uri.parse("content://intent/content");
+ PendingIntent contentIntent = getPendingIntentWithUri(contentIntentUri);
+ Uri deleteIntentUri = Uri.parse("content://intent/delete");
+ PendingIntent deleteIntent = getPendingIntentWithUri(deleteIntentUri);
+ Notification n = new Notification.Builder(mContext, "a")
+ .extend(
+ new Notification.TvExtender()
+ .setContentIntent(contentIntent)
+ .setDeleteIntent(deleteIntent))
+ .build();
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ n.visitUris(visitor);
+
+ verify(visitor, times(1)).accept(eq(contentIntentUri));
+ verify(visitor, times(1)).accept(eq(deleteIntentUri));
+ }
+
+ @Test
+ @EnableFlags({android.app.Flags.FLAG_VISIT_RISKY_URIS})
+ public void testVisitUris_carExtender() {
+ final String testParticipant = "testParticipant";
+ Uri readPendingIntentUri = Uri.parse("content://intent/read");
+ PendingIntent readPendingIntent = getPendingIntentWithUri(readPendingIntentUri);
+ Uri replyPendingIntentUri = Uri.parse("content://intent/reply");
+ PendingIntent replyPendingIntent = getPendingIntentWithUri(replyPendingIntentUri);
+ final RemoteInput testRemoteInput = new RemoteInput.Builder("key").build();
+
+ Notification n = new Notification.Builder(mContext, "a")
+ .extend(new Notification.CarExtender().setUnreadConversation(
+ new Notification.CarExtender.Builder(testParticipant)
+ .setReadPendingIntent(readPendingIntent)
+ .setReplyAction(replyPendingIntent, testRemoteInput)
+ .build()))
+ .build();
+
+ Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class);
+ n.visitUris(visitor);
+
+ verify(visitor, times(1)).accept(eq(readPendingIntentUri));
+ verify(visitor, times(1)).accept(eq(replyPendingIntentUri));
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
index 44dbe385a144..ea948ca0e28b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationVisitUrisTest.java
@@ -146,6 +146,10 @@ public class NotificationVisitUrisTest extends UiServiceTestCase {
.put(Notification.Action.Builder.class, "extend")
// Overwrites icon supplied to constructor.
.put(Notification.BubbleMetadata.Builder.class, "setIcon")
+ // Overwrites intent supplied to constructor.
+ .put(Notification.BubbleMetadata.Builder.class, "setIntent")
+ // Overwrites intent supplied to constructor.
+ .put(Notification.BubbleMetadata.Builder.class, "setDeleteIntent")
// Discards previously-added actions.
.put(RemoteViews.class, "mergeRemoteViews")
.build();
@@ -680,14 +684,14 @@ public class NotificationVisitUrisTest extends UiServiceTestCase {
}
if (clazz == Intent.class) {
- // TODO(b/281044385): Are Intent Uris (new Intent(String,Uri)) relevant?
- return new Intent("action");
+ return new Intent("action", generateUri(where.plus(Intent.class)));
}
if (clazz == PendingIntent.class) {
- // PendingIntent can have an Intent with a Uri but those are inaccessible and
- // not inspected.
- return PendingIntent.getActivity(mContext, 0, new Intent("action"),
+ // PendingIntent can have an Intent with a Uri.
+ Uri intentUri = generateUri(where.plus(PendingIntent.class));
+ return PendingIntent.getActivity(mContext, 0,
+ new Intent("action", intentUri),
PendingIntent.FLAG_IMMUTABLE);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index 670f9f697a5c..526201f9c1c6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -49,7 +49,6 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
-import android.content.pm.UserPackage;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -196,7 +195,7 @@ public class ActivityStartInterceptorTest {
mAInfo.applicationInfo.flags = FLAG_SUSPENDED;
when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
- .thenReturn(UserPackage.of(TEST_USER_ID, PLATFORM_PACKAGE_NAME));
+ .thenReturn(PLATFORM_PACKAGE_NAME);
// THEN calling intercept returns true
assertTrue(mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null, null));
@@ -228,10 +227,9 @@ public class ActivityStartInterceptorTest {
.setMessage("Test Message")
.setIcon(0x11110001)
.build();
- UserPackage suspender = UserPackage.of(TEST_USER_ID, suspendingPackage);
when(mPackageManagerInternal.getSuspendingPackage(TEST_PACKAGE_NAME, TEST_USER_ID))
- .thenReturn(suspender);
- when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspender,
+ .thenReturn(suspendingPackage);
+ when(mPackageManagerInternal.getSuspendedDialogInfo(TEST_PACKAGE_NAME, suspendingPackage,
TEST_USER_ID)).thenReturn(dialogInfo);
return dialogInfo;
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index b167f1bdfe20..d05eb5cd2d4c 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1349,6 +1349,24 @@ public class TelecomManager {
}
/**
+ * Returns a list of {@link PhoneAccountHandle}s which can be used to make and receive phone
+ * calls. The returned list includes those accounts which have been explicitly enabled by
+ * the user or other users visible to the user.
+ *
+ * @see #EXTRA_PHONE_ACCOUNT_HANDLE
+ * @return A list of {@code PhoneAccountHandle} objects.
+ *
+ * @throws IllegalStateException if telecom service is null.
+ */
+ @FlaggedApi(com.android.internal.telephony.flags.Flags.FLAG_WORK_PROFILE_API_SPLIT)
+ @RequiresPermission(allOf = {android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES})
+ public @NonNull List<PhoneAccountHandle> getCallCapablePhoneAccountsAcrossProfiles() {
+ return getCallCapablePhoneAccountsAcrossProfiles(false);
+ }
+
+
+ /**
* Returns a list of {@link PhoneAccountHandle}s for all self-managed
* {@link ConnectionService}s owned by the calling {@link UserHandle}.
* <p>
@@ -1423,7 +1441,7 @@ public class TelecomManager {
if (service != null) {
try {
return service.getCallCapablePhoneAccounts(includeDisabledAccounts,
- mContext.getOpPackageName(), mContext.getAttributionTag()).getList();
+ mContext.getOpPackageName(), mContext.getAttributionTag(), false).getList();
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts("
+ includeDisabledAccounts + ")", e);
@@ -1433,6 +1451,37 @@ public class TelecomManager {
}
/**
+ * Returns a list of {@link PhoneAccountHandle}s visible to current user including those which
+ * have not been enabled by the user.
+ *
+ * @param includeDisabledAccounts When {@code true}, disabled phone accounts will be included,
+ * when {@code false}, only enabled phone accounts will be
+ * included.
+ * @return A list of {@code PhoneAccountHandle} objects.
+ *
+ * @throws IllegalStateException if telecom service is null.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(com.android.internal.telephony.flags.Flags.FLAG_WORK_PROFILE_API_SPLIT)
+ @RequiresPermission(allOf = {android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES})
+ public @NonNull List<PhoneAccountHandle> getCallCapablePhoneAccountsAcrossProfiles(
+ boolean includeDisabledAccounts) {
+ ITelecomService service = getTelecomService();
+ if (service == null) {
+ throw new IllegalStateException("telecom service is null.");
+ }
+
+ try {
+ return service.getCallCapablePhoneAccounts(includeDisabledAccounts,
+ mContext.getOpPackageName(), mContext.getAttributionTag(), true).getList();
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
* Returns a list of all {@link PhoneAccount}s registered for the calling package.
*
* @deprecated Use {@link #getSelfManagedPhoneAccounts()} instead to get only self-managed
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 53154e6063b2..f1bfd227298c 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -61,7 +61,8 @@ interface ITelecomService {
* @see TelecomServiceImpl#getCallCapablePhoneAccounts
*/
ParceledListSlice<PhoneAccountHandle> getCallCapablePhoneAccounts(
- boolean includeDisabledAccounts, String callingPackage, String callingFeatureId);
+ boolean includeDisabledAccounts, String callingPackage,
+ String callingFeatureId, boolean acrossProfiles);
/**
* @see TelecomServiceImpl#getSelfManagedPhoneAccounts
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7cb2cc398c46..bcd99295b605 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -9577,14 +9577,20 @@ public class CarrierConfigManager {
"satellite_attach_supported_bool";
/**
- * The carrier-enabled satellite connection hysteresis time in seconds to determine whether to
- * recommend Dialer to prompt users to use satellite emergency messaging.
+ * The carrier-enabled satellite connection hysteresis time in seconds for which the device
+ * continues in satellite mode after it loses the connection with the satellite network.
* <p>
- * A timer is started when there is an ongoing emergency call, and the IMS is not registered,
- * and cellular service is not available, and the device was connected to a satellite network
- * within this time in the past. When the timer expires, Telephony will send the event
+ * If the device is in satellite mode, the following actions will be taken by the device:
+ * <ul>
+ * <li>System UI will continue showing the satellite icon.</li>
+ * <li>When there is an ongoing emergency call, and the IMS is not registered, and cellular
+ * service is not available, and the device is in satellite mode, a timer with a duration
+ * defined by the overlay config
+ * {@code config_emergency_call_wait_for_connection_timeout_millis} will be started. When the
+ * timer expires, Telephony will send the event
* {@link TelephonyManager#EVENT_DISPLAY_EMERGENCY_MESSAGE} to Dialer, which will then prompt
- * users to switch to using satellite emergency messaging.
+ * users to switch to using satellite emergency messaging.</li>
+ * </ul>
* <p>
* The default value is 300 seconds.
*/
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 60cc9c7f73cf..df349f89fbf8 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -3556,4 +3556,29 @@ public final class SmsManager {
}
return smscUri;
}
+
+ /**
+ * Gets the message size of a WAP from the cache.
+ *
+ * @param locationUrl the location to use as a key for looking up the size in the cache.
+ * The locationUrl may or may not have the transactionId appended to the url.
+ *
+ * @return long representing the message size
+ * @throws java.util.NoSuchElementException if the WAP push doesn't exist in the cache
+ * @throws IllegalArgumentException if the locationUrl is empty
+ *
+ * @hide
+ */
+ public long getWapMessageSize(@NonNull String locationUrl) {
+ try {
+ ISms iSms = getISmsService();
+ if (iSms != null) {
+ return iSms.getWapMessageSize(locationUrl);
+ } else {
+ throw new RuntimeException("Could not acquire ISms service.");
+ }
+ } catch (RemoteException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 55a3da5ad89d..f8166e58cd2f 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1207,7 +1207,8 @@ public class TelephonyManager {
* The dialer app receives this event via
* {@link Call.Callback#onConnectionEvent(Call, String, Bundle)}.
* <p>
- * The {@link Bundle} parameter is expected to include the following extras:
+ * The {@link Bundle} parameter is guaranteed to include the following extras if the below
+ * conditions are met:
* <ul>
* <li>{@link #EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE} - the recommending handover
* type.</li>
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 2172d7de0dd7..71bb329a7281 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -19,6 +19,7 @@ package android.telephony.ims;
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresFeature;
@@ -45,6 +46,7 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.ITelephony;
+import com.android.internal.telephony.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -447,6 +449,114 @@ public class ImsMmTelManager implements RegistrationManager {
}
/**
+ * Registers a {@link RegistrationCallback} with the system, which will provide IMS emergency
+ * registration updates for the subscription specified in
+ * {@link ImsManager#getImsMmTelManager(int)}. Use
+ * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
+ * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
+ *
+ * When the callback is registered, it will initiate the callback c to be called with the
+ * current emergency registration state.
+ * Emergency registration callback is available when there is valid SIM card.
+ * <p>This API requires one of the following:
+ * <ul>
+ * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
+ * <li>If the caller is the device or profile owner, the caller holds the
+ * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
+ * <li>The caller has carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
+ * active subscription.</li>
+ * </ul>
+ * <p>The profile owner is an app that owns a managed profile on the device; for more details
+ * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+ * Access by profile owners is deprecated and will be removed in a future release.
+ *
+ * @param executor The executor the callback events should be run on.
+ * @param c The {@link RegistrationCallback} to be added.
+ * @see #unregisterImsEmergencyRegistrationCallback
+ * @throws ImsException if the subscription associated with this callback is valid, but
+ * the {@link ImsService} associated with the subscription is not available. This can happen if
+ * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
+ * reason.
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
+ public void registerImsEmergencyRegistrationCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull RegistrationManager.RegistrationCallback c) throws ImsException {
+ if (c == null) {
+ throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+ }
+ if (executor == null) {
+ throw new IllegalArgumentException("Must include a non-null Executor.");
+ }
+ c.setExecutor(executor);
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
+ try {
+ iTelephony.registerImsEmergencyRegistrationCallback(mSubId, c.getBinder());
+ } catch (ServiceSpecificException e) {
+ throw new ImsException(e.getMessage(), e.errorCode);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ } catch (IllegalStateException e) {
+ throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Removes an existing {@link RegistrationCallback} for Emergency IMS registration.
+ *
+ * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+ * etc...), this callback will automatically be removed. If this method is called for an
+ * inactive subscription, it will result in a no-op.
+ * <p>This API requires one of the following:
+ * <ul>
+ * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li>
+ * <li>If the caller is the device or profile owner, the caller holds the
+ * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li>
+ * <li>The caller has carrier privileges (see
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any
+ * active subscription.</li>
+ * </ul>
+ * <p>The profile owner is an app that owns a managed profile on the device; for more details
+ * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>.
+ * Access by profile owners is deprecated and will be removed in a future release.
+ *
+ * @param c The {@link RegistrationCallback} to be removed.
+ * @see android.telephony.SubscriptionManager.OnSubscriptionsChangedListener
+ * @see #registerImsEmergencyRegistrationCallback(Executor,
+ * RegistrationManager.RegistrationCallback)
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
+ public void unregisterImsEmergencyRegistrationCallback(
+ @NonNull RegistrationManager.RegistrationCallback c) {
+ if (c == null) {
+ throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
+ }
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ Log.w("ImsMmTelManager", "Could not find Telephony Service.");
+ return;
+ }
+
+ try {
+ iTelephony.unregisterImsEmergencyRegistrationCallback(mSubId, c.getBinder());
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
* {@inheritDoc}
* @hide
*/
diff --git a/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java
index 50c438c7678e..f548dbada3cb 100644
--- a/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java
+++ b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java
@@ -16,6 +16,7 @@
package android.telephony.ims;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,6 +27,8 @@ import android.telephony.AccessNetworkConstants;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.ArraySet;
+import com.android.internal.telephony.flags.Flags;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -46,12 +49,36 @@ public final class ImsRegistrationAttributes implements Parcelable {
*
*/
public static final int ATTR_EPDG_OVER_CELL_INTERNET = 1 << 0;
+ /**
+ * Attribute to specify if ims registration is of type normal or emergency.
+ * <p>
+ * For emergency registration bit will be set.
+ * For normal registration bit will not be set.
+ * This flag is only applicable when listening to emergency IMS registration state updates
+ * via the ImsMmTelManager#registerImsEmergencyRegistrationCallback API
+ * </p>
+ */
+ @FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
+ public static final int ATTR_REGISTRATION_TYPE_EMERGENCY = 1 << 1;
+ /**
+ * Attribute to specify if virtual registration is required.
+ * <p>
+ * If emergency registration is not required for making emergency call, in such cases
+ * bit will be set and callback will represent virtual registration status update.
+ * This flag is only applicable when listening to emergency IMS registration state updates
+ * via the ImsMmTelManager#registerImsEmergencyRegistrationCallback API
+ * </p>
+ */
+ @FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
+ public static final int ATTR_VIRTUAL_FOR_ANONYMOUS_EMERGENCY_CALL = 1 << 2;
/** @hide */
// Defines the underlying radio technology type that we have registered for IMS over.
@IntDef(prefix = "ATTR_",
value = {
ATTR_EPDG_OVER_CELL_INTERNET,
+ ATTR_REGISTRATION_TYPE_EMERGENCY,
+ ATTR_VIRTUAL_FOR_ANONYMOUS_EMERGENCY_CALL,
},
flag = true)
@Retention(RetentionPolicy.SOURCE)
@@ -67,6 +94,8 @@ public final class ImsRegistrationAttributes implements Parcelable {
private Set<String> mFeatureTags = Collections.emptySet();
private @Nullable SipDetails mSipDetails;
+ private @ImsAttributeFlag int mAttributeFlags;
+
/**
* Build a new instance of {@link ImsRegistrationAttributes}.
*
@@ -74,6 +103,9 @@ public final class ImsRegistrationAttributes implements Parcelable {
*/
public Builder(@ImsRegistrationImplBase.ImsRegistrationTech int registrationTech) {
mRegistrationTech = registrationTech;
+ if (registrationTech == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
+ mAttributeFlags |= ATTR_EPDG_OVER_CELL_INTERNET;
+ }
}
/**
@@ -110,25 +142,32 @@ public final class ImsRegistrationAttributes implements Parcelable {
}
/**
+ * Set the attribute flag ATTR_REGISTRATION_TYPE_EMERGENCY.
+ */
+ @FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
+ public @NonNull Builder setFlagRegistrationTypeEmergency() {
+ mAttributeFlags |= ATTR_REGISTRATION_TYPE_EMERGENCY;
+ return this;
+ }
+
+ /**
+ * Set the attribute flag ATTR_VIRTUAL_FOR_ANONYMOUS_EMERGENCY_CALL.
+ */
+ @FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
+ public @NonNull Builder setFlagVirtualRegistrationForEmergencyCall() {
+ mAttributeFlags |= ATTR_VIRTUAL_FOR_ANONYMOUS_EMERGENCY_CALL;
+ return this;
+ }
+
+ /**
* @return A new instance created from this builder.
*/
public @NonNull ImsRegistrationAttributes build() {
return new ImsRegistrationAttributes(mRegistrationTech,
RegistrationManager.getAccessType(mRegistrationTech),
- getAttributeFlags(mRegistrationTech),
+ mAttributeFlags,
mFeatureTags, mSipDetails);
}
-
- /**
- * @return attribute flags from the registration technology.
- */
- private static int getAttributeFlags(int imsRadioTech) {
- int attributes = 0;
- if (imsRadioTech == ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM) {
- attributes |= ATTR_EPDG_OVER_CELL_INTERNET;
- }
- return attributes;
- }
}
private final int mRegistrationTech;
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl b/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl
index 219c9c88d825..2a6b8f292d0b 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRegistration.aidl
@@ -28,6 +28,8 @@ interface IImsRegistration {
int getRegistrationTechnology();
oneway void addRegistrationCallback(IImsRegistrationCallback c);
oneway void removeRegistrationCallback(IImsRegistrationCallback c);
+ oneway void addEmergencyRegistrationCallback(IImsRegistrationCallback c);
+ oneway void removeEmergencyRegistrationCallback(IImsRegistrationCallback c);
oneway void triggerFullNetworkRegistration(int sipCode, String sipReason);
oneway void triggerUpdateSipDelegateRegistration();
oneway void triggerSipDelegateDeregistration();
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index ff378ba02856..99c26b01bf01 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -16,6 +16,7 @@
package android.telephony.ims.stub;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -31,6 +32,7 @@ import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.util.Log;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.telephony.util.RemoteCallbackListExt;
import com.android.internal.telephony.util.TelephonyUtils;
import com.android.internal.util.ArrayUtils;
@@ -56,7 +58,6 @@ import java.util.function.Supplier;
public class ImsRegistrationImplBase {
private static final String LOG_TAG = "ImsRegistrationImplBase";
-
/**
* @hide
*/
@@ -233,6 +234,31 @@ public class ImsRegistrationImplBase {
}
@Override
+ public void addEmergencyRegistrationCallback(IImsRegistrationCallback c)
+ throws RemoteException {
+ AtomicReference<RemoteException> exceptionRef = new AtomicReference<>();
+ executeMethodAsync(() -> {
+ try {
+ ImsRegistrationImplBase.this.addEmergencyRegistrationCallback(c);
+ } catch (RemoteException e) {
+ exceptionRef.set(e);
+ }
+ }, "addEmergencyRegistrationCallback");
+
+ if (exceptionRef.get() != null) {
+ throw exceptionRef.get();
+ }
+ }
+
+ @Override
+ public void removeEmergencyRegistrationCallback(IImsRegistrationCallback c)
+ throws RemoteException {
+ executeMethodAsync(() ->
+ ImsRegistrationImplBase.this.removeEmergencyRegistrationCallback(c),
+ "removeEmergencyRegistrationCallback");
+ }
+
+ @Override
public void removeRegistrationCallback(IImsRegistrationCallback c) throws RemoteException {
executeMethodAsync(() -> ImsRegistrationImplBase.this.removeRegistrationCallback(c),
"removeRegistrationCallback");
@@ -302,16 +328,23 @@ public class ImsRegistrationImplBase {
private final RemoteCallbackListExt<IImsRegistrationCallback> mCallbacks =
new RemoteCallbackListExt<>();
+ private final RemoteCallbackListExt<IImsRegistrationCallback> mEmergencyCallbacks =
+ new RemoteCallbackListExt<>();
private final Object mLock = new Object();
// Locked on mLock
private ImsRegistrationAttributes mRegistrationAttributes;
+ private ImsRegistrationAttributes mEmergencyRegistrationAttributes;
// Locked on mLock
private int mRegistrationState = REGISTRATION_STATE_UNKNOWN;
+ private int mEmergencyRegistrationState = REGISTRATION_STATE_UNKNOWN;
// Locked on mLock, create unspecified disconnect cause.
private ImsReasonInfo mLastDisconnectCause = new ImsReasonInfo();
+ private ImsReasonInfo mEmergencyLastDisconnectCause = new ImsReasonInfo();
// Locked on mLock
private int mLastDisconnectSuggestedAction = RegistrationManager.SUGGESTED_ACTION_NONE;
+ private int mEmergencyLastDisconnectSuggestedAction = RegistrationManager.SUGGESTED_ACTION_NONE;
private int mLastDisconnectRadioTech = REGISTRATION_TECH_NONE;
+ private int mEmergencyLastDisconnectRadioTech = REGISTRATION_TECH_NONE;
// We hold onto the uris each time they change so that we can send it to a callback when its
// first added.
@@ -331,7 +364,7 @@ public class ImsRegistrationImplBase {
// do not want to risk introducing a deadlock by using the same mCallbacks Object to
// synchronize on outgoing and incoming operations.
mCallbacks.register(c);
- updateNewCallbackWithState(c);
+ updateNewCallbackWithState(c, false);
}
private void removeRegistrationCallback(IImsRegistrationCallback c) {
@@ -342,6 +375,16 @@ public class ImsRegistrationImplBase {
mCallbacks.unregister(c);
}
+ private void addEmergencyRegistrationCallback(IImsRegistrationCallback c)
+ throws RemoteException {
+ mEmergencyCallbacks.register(c);
+ updateNewCallbackWithState(c, true);
+ }
+
+ private void removeEmergencyRegistrationCallback(IImsRegistrationCallback c) {
+ mEmergencyCallbacks.unregister(c);
+ }
+
/**
* Called by the framework to request that the ImsService perform the network registration
* of all SIP delegates associated with this ImsService.
@@ -428,14 +471,19 @@ public class ImsRegistrationImplBase {
*/
@SystemApi
public final void onRegistered(@NonNull ImsRegistrationAttributes attributes) {
- updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERED);
+ boolean isEmergency = isEmergency(attributes);
+ if (isEmergency) {
+ updateToEmergencyState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERED);
+ } else {
+ updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERED);
+ }
broadcastToCallbacksLocked((c) -> {
try {
c.onRegistered(attributes);
} catch (RemoteException e) {
Log.w(LOG_TAG, e + "onRegistered(int, Set) - Skipping callback.");
}
- });
+ }, isEmergency);
}
/**
@@ -457,14 +505,19 @@ public class ImsRegistrationImplBase {
*/
@SystemApi
public final void onRegistering(@NonNull ImsRegistrationAttributes attributes) {
- updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERING);
+ boolean isEmergency = isEmergency(attributes);
+ if (isEmergency) {
+ updateToEmergencyState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERING);
+ } else {
+ updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERING);
+ }
broadcastToCallbacksLocked((c) -> {
try {
c.onRegistering(attributes);
} catch (RemoteException e) {
Log.w(LOG_TAG, e + "onRegistering(int, Set) - Skipping callback.");
}
- });
+ }, isEmergency);
}
/**
@@ -513,16 +566,57 @@ public class ImsRegistrationImplBase {
public final void onDeregistered(@Nullable ImsReasonInfo info,
@RegistrationManager.SuggestedAction int suggestedAction,
@ImsRegistrationTech int imsRadioTech) {
- updateToDisconnectedState(info, suggestedAction, imsRadioTech);
+ // Impl to keep backwards compatibility with old implementations
+ ImsRegistrationAttributes attributes = mRegistrationAttributes != null
+ ? new ImsRegistrationAttributes(imsRadioTech,
+ mRegistrationAttributes.getTransportType(),
+ mRegistrationAttributes.getAttributeFlags(),
+ mRegistrationAttributes.getFeatureTags()) :
+ new ImsRegistrationAttributes.Builder(imsRadioTech).build();
+ onDeregistered(info, suggestedAction, attributes);
+ }
+
+ /**
+ * Notify the framework that the device is disconnected from the IMS network.
+ * <p>
+ * Note: Prior to calling {@link #onDeregistered(ImsReasonInfo,int)}, you should ensure that any
+ * changes to {@link android.telephony.ims.feature.ImsFeature} capability availability is sent
+ * to the framework. For example,
+ * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}
+ * and
+ * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}
+ * may be set to unavailable to ensure the framework knows these services are no longer
+ * available due to de-registration. If you do not report capability changes impacted by
+ * de-registration, the framework will not know which features are no longer available as a
+ * result.
+ *
+ * @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
+ * @param suggestedAction the expected behavior of radio protocol stack.
+ * @param attributes The attributes associated with the IMS registration
+ * @hide This API is not part of the Android public SDK API
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
+ public final void onDeregistered(@Nullable ImsReasonInfo info,
+ @RegistrationManager.SuggestedAction int suggestedAction,
+ @NonNull ImsRegistrationAttributes attributes) {
+ boolean isEmergency = isEmergency(attributes);
+ int imsRadioTech = attributes.getRegistrationTechnology();
+ if (isEmergency) {
+ updateToDisconnectedEmergencyState(info, suggestedAction, imsRadioTech);
+ } else {
+ updateToDisconnectedState(info, suggestedAction, imsRadioTech);
+ }
// ImsReasonInfo should never be null.
final ImsReasonInfo reasonInfo = (info != null) ? info : new ImsReasonInfo();
+
broadcastToCallbacksLocked((c) -> {
try {
c.onDeregistered(reasonInfo, suggestedAction, imsRadioTech);
} catch (RemoteException e) {
Log.w(LOG_TAG, e + "onDeregistered() - Skipping callback.");
}
- });
+ }, isEmergency);
}
/**
@@ -568,6 +662,7 @@ public class ImsRegistrationImplBase {
*
* @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
* @param suggestedAction the expected behavior of radio protocol stack.
+ * @param imsRadioTech the network type on which IMS registration has failed.
* @param details the {@link SipDetails} related to disconnected Ims registration
* @hide This API is not part of the Android public SDK API
*/
@@ -584,7 +679,7 @@ public class ImsRegistrationImplBase {
} catch (RemoteException e) {
Log.w(LOG_TAG, e + "onDeregistered() - Skipping callback.");
}
- });
+ }, false);
}
/**
@@ -599,14 +694,38 @@ public class ImsRegistrationImplBase {
@SystemApi
public final void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech,
ImsReasonInfo info) {
+ ImsRegistrationAttributes attributes = mRegistrationAttributes != null
+ ? new ImsRegistrationAttributes(imsRadioTech,
+ mRegistrationAttributes.getTransportType(),
+ mRegistrationAttributes.getAttributeFlags(),
+ mRegistrationAttributes.getFeatureTags()) :
+ new ImsRegistrationAttributes.Builder(imsRadioTech).build();
+ onTechnologyChangeFailed(info, attributes);
+ }
+
+ /**
+ * Notify the framework that the handover from the current radio technology to the technology
+ * defined in {@code imsRadioTech} has failed.
+ * {@link #REGISTRATION_TECH_LTE}, {@link #REGISTRATION_TECH_IWLAN} and
+ * {@link #REGISTRATION_TECH_CROSS_SIM}.
+ * @param info The {@link ImsReasonInfo} for the failure to change technology.
+ * @param attributes The attributes associated with the IMS registration
+ * @hide This API is not part of the Android public SDK API
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_EMERGENCY_REGISTRATION_STATE)
+ public final void onTechnologyChangeFailed(@Nullable ImsReasonInfo info,
+ @NonNull ImsRegistrationAttributes attributes) {
+ boolean isEmergency = isEmergency(attributes);
+ int imsRadioTech = attributes.getRegistrationTechnology();
final ImsReasonInfo reasonInfo = (info != null) ? info : new ImsReasonInfo();
- broadcastToCallbacksLocked((c) -> {
+ broadcastToCallbacksLocked(c -> {
try {
c.onTechnologyChangeFailed(imsRadioTech, reasonInfo);
} catch (RemoteException e) {
Log.w(LOG_TAG, e + "onTechnologyChangeFailed() - Skipping callback.");
}
- });
+ }, isEmergency);
}
/**
@@ -623,19 +742,35 @@ public class ImsRegistrationImplBase {
mUris = ArrayUtils.cloneOrNull(uris);
mUrisSet = true;
}
- broadcastToCallbacksLocked((c) -> onSubscriberAssociatedUriChanged(c, uris));
+ broadcastToCallbacksLocked((c) -> onSubscriberAssociatedUriChanged(c, uris), false);
+ }
+
+ private boolean isEmergency(ImsRegistrationAttributes attributes) {
+ if (attributes == null) {
+ return false;
+ } else {
+ return (attributes.getAttributeFlags()
+ & ImsRegistrationAttributes.ATTR_REGISTRATION_TYPE_EMERGENCY) != 0;
+ }
}
/**
- * Broadcast the specified operation in a synchronized manner so that multiple threads do not
+ * Broadcast the specified operation in ta synchronized manner so that multiple threads do not
* try to call broadcast at the same time, which will generate an error.
* @param c The Consumer lambda method containing the callback to call.
*/
- private void broadcastToCallbacksLocked(Consumer<IImsRegistrationCallback> c) {
+ private void broadcastToCallbacksLocked(Consumer<IImsRegistrationCallback> c,
+ boolean isEmergency) {
// One broadcast can happen at a time, so synchronize threads so only one
// beginBroadcast/endBroadcast happens at a time.
- synchronized (mCallbacks) {
- mCallbacks.broadcastAction(c);
+ if (isEmergency) {
+ synchronized (mEmergencyCallbacks) {
+ mEmergencyCallbacks.broadcastAction(c);
+ }
+ } else {
+ synchronized (mCallbacks) {
+ mCallbacks.broadcastAction(c);
+ }
}
}
@@ -657,6 +792,16 @@ public class ImsRegistrationImplBase {
}
}
+ private void updateToEmergencyState(ImsRegistrationAttributes attributes, int newState) {
+ synchronized (mLock) {
+ mEmergencyRegistrationAttributes = attributes;
+ mEmergencyRegistrationState = newState;
+ mEmergencyLastDisconnectCause = null;
+ mEmergencyLastDisconnectSuggestedAction = RegistrationManager.SUGGESTED_ACTION_NONE;
+ mEmergencyLastDisconnectRadioTech = REGISTRATION_TECH_NONE;
+ }
+ }
+
private void updateToDisconnectedState(ImsReasonInfo info,
@RegistrationManager.SuggestedAction int suggestedAction,
@ImsRegistrationTech int imsRadioTech) {
@@ -678,11 +823,33 @@ public class ImsRegistrationImplBase {
}
}
+ private void updateToDisconnectedEmergencyState(ImsReasonInfo info,
+ @RegistrationManager.SuggestedAction int suggestedAction,
+ @ImsRegistrationTech int imsRadioTech) {
+ synchronized (mLock) {
+ //We don't want to send this info over if we are disconnected
+ mUrisSet = false;
+ mUris = null;
+
+ updateToEmergencyState(new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_NONE)
+ .build(),
+ RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
+ if (info != null) {
+ mEmergencyLastDisconnectCause = info;
+ mEmergencyLastDisconnectSuggestedAction = suggestedAction;
+ mEmergencyLastDisconnectRadioTech = imsRadioTech;
+ } else {
+ Log.w(LOG_TAG, "updateToDisconnectedState: no ImsReasonInfo provided.");
+ mEmergencyLastDisconnectCause = new ImsReasonInfo();
+ }
+ }
+ }
+
/**
* @param c the newly registered callback that will be updated with the current registration
* state.
*/
- private void updateNewCallbackWithState(IImsRegistrationCallback c)
+ private void updateNewCallbackWithState(IImsRegistrationCallback c, boolean isEmergencyCallback)
throws RemoteException {
int state;
ImsRegistrationAttributes attributes;
@@ -692,11 +859,15 @@ public class ImsRegistrationImplBase {
boolean urisSet;
Uri[] uris;
synchronized (mLock) {
- state = mRegistrationState;
- attributes = mRegistrationAttributes;
- disconnectInfo = mLastDisconnectCause;
- suggestedAction = mLastDisconnectSuggestedAction;
- imsDisconnectRadioTech = mLastDisconnectRadioTech;
+ state = isEmergencyCallback ? mEmergencyRegistrationState : mRegistrationState;
+ attributes = isEmergencyCallback ? mEmergencyRegistrationAttributes :
+ mRegistrationAttributes;
+ disconnectInfo = isEmergencyCallback ? mEmergencyLastDisconnectCause :
+ mLastDisconnectCause;
+ suggestedAction = isEmergencyCallback ? mEmergencyLastDisconnectSuggestedAction :
+ mLastDisconnectSuggestedAction;
+ imsDisconnectRadioTech = isEmergencyCallback ? mEmergencyLastDisconnectRadioTech :
+ mLastDisconnectRadioTech;
urisSet = mUrisSet;
uris = mUris;
}
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 0e23f364134c..799ac642fca1 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -592,4 +592,17 @@ interface ISms {
* @hide
*/
boolean resetAllCellBroadcastRanges(int subId);
+
+ /**
+ * Gets the message size of a WAP from the cache.
+ *
+ * @param locationUrl the location to use as a key for looking up the size in the cache.
+ * The locationUrl may or may not have the transactionId appended to the url.
+ *
+ * @return long representing the message size
+ * @throws java.util.NoSuchElementException if the WAP push doesn't exist in the cache
+ *
+ * @hide
+ */
+ long getWapMessageSize(String locationUrl);
}
diff --git a/telephony/java/com/android/internal/telephony/ISmsImplBase.java b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
index 686455688203..70bc4dda2ca7 100644
--- a/telephony/java/com/android/internal/telephony/ISmsImplBase.java
+++ b/telephony/java/com/android/internal/telephony/ISmsImplBase.java
@@ -227,4 +227,10 @@ public class ISmsImplBase extends ISms.Stub {
public boolean resetAllCellBroadcastRanges(int subId) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public long getWapMessageSize(String locationUrl) {
+ throw new UnsupportedOperationException();
+ }
+
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 37752d0cecd8..84777c9441a1 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1901,6 +1901,16 @@ interface ITelephony {
void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c);
/**
+ * Adds an IMS emergency registration status callback for the subscription id specified.
+ */
+ void registerImsEmergencyRegistrationCallback(int subId, IImsRegistrationCallback c);
+ /**
+ * Removes an existing IMS emergency registration status callback for the subscription
+ * id specified.
+ */
+ void unregisterImsEmergencyRegistrationCallback(int subId, IImsRegistrationCallback c);
+
+ /**
* Get the IMS service registration state for the MmTelFeature associated with this sub id.
*/
void getImsMmTelRegistrationState(int subId, IIntegerConsumer consumer);
@@ -3035,8 +3045,8 @@ interface ITelephony {
*
* @param handoverType The type of handover from emergency call to satellite messaging. Use one
* of the following values to enable the override:
- * 0 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS
- * 1 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911
+ * 1 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS
+ * 2 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911
* To disable the override, use -1 for handoverType.
* @param delaySeconds The event EVENT_DISPLAY_EMERGENCY_MESSAGE will be sent to Dialer
* delaySeconds after the emergency call starts.