summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp31
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java2
-rw-r--r--apex/media/framework/Android.bp2
-rw-r--r--api/api.go27
-rw-r--r--boot/hiddenapi/hiddenapi-max-target-o.txt213
-rw-r--r--core/api/current.txt95
-rw-r--r--core/api/module-lib-current.txt31
-rw-r--r--core/api/removed.txt2
-rw-r--r--core/api/system-current.txt57
-rw-r--r--core/api/system-lint-baseline.txt8
-rw-r--r--core/api/test-current.txt6
-rw-r--r--core/java/Android.bp12
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java27
-rw-r--r--core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl2
-rw-r--r--core/java/android/app/Activity.java35
-rw-r--r--core/java/android/app/ActivityManagerInternal.java8
-rw-r--r--core/java/android/app/ApplicationExitInfo.java9
-rw-r--r--core/java/android/app/Dialog.java10
-rw-r--r--core/java/android/app/IActivityManager.aidl4
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl3
-rw-r--r--core/java/android/app/SystemServiceRegistry.java11
-rw-r--r--core/java/android/app/UiAutomation.java27
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java60
-rw-r--r--core/java/android/app/admin/DevicePolicyResources.java60
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--core/java/android/companion/TEST_MAPPING9
-rw-r--r--core/java/android/content/Context.java37
-rw-r--r--core/java/android/content/Intent.java6
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java84
-rw-r--r--core/java/android/content/pm/PackageManager.java1
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java11
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java2
-rw-r--r--core/java/android/inputmethodservice/NavigationBarController.java3
-rw-r--r--core/java/android/os/BatteryStatsManager.java6
-rw-r--r--core/java/android/os/logcat/ILogcatManagerService.aidl2
-rw-r--r--core/java/android/permission/IPermissionManager.aidl3
-rw-r--r--core/java/android/permission/PermissionControllerManager.java14
-rw-r--r--core/java/android/permission/PermissionControllerService.java10
-rw-r--r--core/java/android/permission/PermissionManager.java35
-rw-r--r--core/java/android/service/games/GameSession.java76
-rw-r--r--core/java/android/service/games/GameSessionActivityCallback.java54
-rw-r--r--core/java/android/service/games/GameSessionActivityResult.java71
-rw-r--r--core/java/android/service/games/GameSessionTrampolineActivity.java79
-rw-r--r--core/java/android/view/OnBackInvokedDispatcher.java8
-rw-r--r--core/java/android/view/OnBackInvokedDispatcherOwner.java4
-rw-r--r--core/java/android/view/View.java23
-rw-r--r--core/java/android/view/ViewRootImpl.java29
-rw-r--r--core/java/android/view/animation/Animation.java12
-rw-r--r--core/java/android/view/animation/ClipRectAnimation.java17
-rw-r--r--core/java/android/view/animation/ExtendAnimation.java16
-rw-r--r--core/java/android/view/animation/GridLayoutAnimationController.java6
-rw-r--r--core/java/android/view/animation/LayoutAnimationController.java2
-rw-r--r--core/java/android/view/animation/RotateAnimation.java4
-rw-r--r--core/java/android/view/animation/ScaleAnimation.java4
-rw-r--r--core/java/android/view/animation/TranslateAnimation.java8
-rw-r--r--core/java/android/window/BackNavigationInfo.java68
-rw-r--r--core/java/android/window/ProxyOnBackInvokedDispatcher.java162
-rw-r--r--core/java/com/android/internal/app/BlockedAppActivity.java44
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java6
-rw-r--r--core/java/com/android/internal/policy/DecorView.java20
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java16
-rw-r--r--core/java/com/android/internal/power/MeasuredEnergyStats.java8
-rw-r--r--core/java/com/android/internal/view/RootViewSurfaceTaker.java4
-rw-r--r--core/jni/android_media_AudioSystem.cpp51
-rw-r--r--core/jni/android_util_Process.cpp82
-rw-r--r--core/proto/android/server/powermanagerservice.proto8
-rw-r--r--core/res/AndroidManifest.xml21
-rw-r--r--core/res/res/values/attrs.xml8
-rw-r--r--core/res/res/values/strings.xml23
-rw-r--r--core/res/res/values/symbols.xml8
-rw-r--r--core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml1
-rw-r--r--core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java2
-rw-r--r--core/tests/coretests/src/android/window/BackNavigationTest.java134
-rw-r--r--core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java8
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--data/etc/services.core.protolog.json18
-rw-r--r--libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more.xml25
-rw-r--r--libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more_ripple.xml20
-rw-r--r--libs/WindowManager/Shell/res/layout/letterbox_education_toast_layout.xml61
-rw-r--r--libs/WindowManager/Shell/res/values/dimen.xml12
-rw-r--r--libs/WindowManager/Shell/res/values/strings.xml6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduToastLayout.java69
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl18
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java12
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java112
-rw-r--r--libs/WindowManager/Shell/tests/flicker/AndroidTest.xml8
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java3
-rw-r--r--media/Android.bp5
-rw-r--r--media/java/android/media/AudioDescriptor.java79
-rw-r--r--media/java/android/media/AudioDeviceAttributes.java131
-rw-r--r--media/java/android/media/AudioDeviceInfo.java2
-rw-r--r--media/java/android/media/AudioManager.java30
-rw-r--r--media/java/android/media/AudioProfile.java89
-rw-r--r--media/java/android/media/AudioSystem.java23
-rw-r--r--media/java/android/media/BluetoothProfileConnectionInfo.aidl (renamed from media/java/android/media/BtProfileConnectionInfo.aidl)2
-rw-r--r--media/java/android/media/BluetoothProfileConnectionInfo.java (renamed from media/java/android/media/BtProfileConnectionInfo.java)54
-rwxr-xr-xmedia/java/android/media/IAudioService.aidl7
-rw-r--r--media/java/android/media/ImageReader.java62
-rw-r--r--media/java/android/media/audio/common/AidlConversion.java350
-rw-r--r--media/java/android/media/tv/tuner/DemuxCapabilities.java9
-rw-r--r--media/java/android/media/tv/tuner/filter/Filter.java10
-rw-r--r--media/java/android/media/tv/tuner/filter/RecordSettings.java10
-rw-r--r--media/java/android/media/tv/tuner/filter/SharedFilter.java2
-rw-r--r--media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java6
-rw-r--r--media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java18
-rw-r--r--media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java3
-rw-r--r--media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java18
-rw-r--r--media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java12
-rw-r--r--media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java9
-rw-r--r--media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java21
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendSettings.java3
-rw-r--r--media/java/android/media/tv/tuner/frontend/FrontendStatus.java27
-rw-r--r--media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java6
-rw-r--r--media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java6
-rw-r--r--media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java13
-rwxr-xr-xmedia/java/android/mtp/MtpDatabase.java10
-rw-r--r--media/java/android/mtp/MtpStorage.java15
-rw-r--r--media/java/android/mtp/MtpStorageManager.java46
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BluetoothProfileConnectionInfoTest.java (renamed from media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java)25
-rw-r--r--media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java7
-rw-r--r--media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java107
-rw-r--r--packages/ConnectivityT/framework-t/Android.bp2
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java9
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java3
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java263
-rw-r--r--packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java39
-rw-r--r--packages/ConnectivityT/service/Android.bp2
-rw-r--r--packages/ConnectivityT/service/src/com/android/server/IpSecService.java29
-rw-r--r--packages/ConnectivityT/service/src/com/android/server/NsdService.java134
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java14
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java13
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java5
-rw-r--r--packages/Shell/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt2
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt16
-rw-r--r--packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt3
-rw-r--r--packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt14
-rw-r--r--packages/SystemUI/res/layout/clipboard_overlay.xml241
-rw-r--r--packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml2
-rw-r--r--packages/SystemUI/res/values/strings.xml4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialog.kt141
-rw-r--r--packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogController.kt151
-rw-r--r--packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogFactory.kt63
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java53
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java163
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamComplication.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt105
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt78
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt430
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java70
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsController.kt52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt171
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt123
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java50
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationUtilsTest.java39
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt201
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt164
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java340
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java97
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java24
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt73
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java16
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java16
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java23
-rw-r--r--services/companion/TEST_MAPPING6
-rw-r--r--services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java13
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java16
-rw-r--r--services/core/java/com/android/server/SystemServiceManager.java15
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java35
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java24
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java12
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java25
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java25
-rw-r--r--services/core/java/com/android/server/am/CachedAppOptimizer.java10
-rw-r--r--services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java26
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java25
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceInventory.java130
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java22
-rw-r--r--services/core/java/com/android/server/audio/AudioServiceEvents.java7
-rw-r--r--services/core/java/com/android/server/audio/AudioSystemAdapter.java13
-rw-r--r--services/core/java/com/android/server/audio/BtHelper.java31
-rw-r--r--services/core/java/com/android/server/display/BrightnessMappingStrategy.java8
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceConfig.java262
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java61
-rw-r--r--services/core/java/com/android/server/display/HighBrightnessModeController.java32
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java41
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java18
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java3
-rw-r--r--services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java130
-rw-r--r--services/core/java/com/android/server/logcat/LogcatManagerService.java312
-rw-r--r--services/core/java/com/android/server/media/BluetoothRouteProvider.java8
-rw-r--r--services/core/java/com/android/server/pm/AppDataHelper.java6
-rw-r--r--services/core/java/com/android/server/pm/DexOptHelper.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java91
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java18
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java7
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java13
-rw-r--r--services/core/java/com/android/server/security/AttestationVerificationManagerService.java20
-rw-r--r--services/core/java/com/android/server/security/AttestationVerificationSelfTrustedVerifierForTesting.java224
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java38
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java52
-rw-r--r--services/core/java/com/android/server/wm/Session.java14
-rw-r--r--services/core/java/com/android/server/wm/Task.java36
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java36
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java34
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp13
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp4
-rw-r--r--services/core/xsd/display-device-config/display-device-config.xsd43
-rw-r--r--services/core/xsd/display-device-config/schema/current.txt25
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java50
-rw-r--r--services/java/com/android/server/SystemServer.java20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java20
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java43
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java22
-rw-r--r--services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java60
-rw-r--r--services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java24
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java7
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java29
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java1
-rw-r--r--services/usb/java/com/android/server/usb/UsbAlsaDevice.java16
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java14
-rw-r--r--telephony/java/android/telephony/Annotation.java19
-rw-r--r--telephony/java/android/telephony/SmsMessage.java2
-rw-r--r--telephony/java/android/telephony/data/DataProfile.java11
-rw-r--r--telephony/java/android/telephony/data/DataServiceCallback.java13
-rw-r--r--telephony/java/android/telephony/data/TrafficDescriptor.java224
-rw-r--r--telephony/java/android/telephony/ims/RcsClientConfiguration.java14
-rw-r--r--tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt142
-rw-r--r--tests/FlickerTests/AndroidTest.xml8
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt13
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt2
-rw-r--r--tests/vcn/Android.bp2
-rw-r--r--tests/vcn/AndroidManifest.xml3
283 files changed, 7076 insertions, 3257 deletions
diff --git a/Android.bp b/Android.bp
index e03f8449891a..d5d5150886d4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -155,32 +155,9 @@ java_library_with_nonpublic_deps {
name: "framework-all",
installable: false,
static_libs: [
- "android.net.ipsec.ike.impl",
+ "all-framework-module-impl",
"framework-minus-apex",
- "framework-appsearch.impl",
- "framework-connectivity.impl",
- "framework-connectivity-tiramisu.impl",
- "framework-graphics.impl",
- "framework-mediaprovider.impl",
- "framework-permission.impl",
- "framework-permission-s.impl",
- "framework-scheduling.impl",
- "framework-sdkextensions.impl",
- "framework-statsd.impl",
- "framework-supplementalprocess.impl",
- "framework-tethering.impl",
- "framework-uwb.impl",
- "framework-wifi.impl",
- "updatable-media",
],
- soong_config_variables: {
- include_nonpublic_framework_api: {
- static_libs: [
- "framework-auxiliary.impl",
- "framework-supplementalapi.impl",
- ],
- },
- },
apex_available: ["//apex_available:platform"],
sdk_version: "core_platform",
visibility: [
@@ -308,6 +285,8 @@ java_defaults {
include_dirs: [
"frameworks/av/aidl",
"frameworks/native/libs/permission/aidl",
+ // TODO: remove when moved to the below package
+ "frameworks/base/packages/ConnectivityT/framework-t/aidl-export",
"packages/modules/Connectivity/framework/aidl-export",
],
},
@@ -416,7 +395,6 @@ java_library {
static_libs: [
"app-compat-annotations",
"framework-minus-apex",
- "framework-appsearch.impl", // TODO(b/146218515): should be removed
"framework-updatable-stubs-module_libs_api",
],
sdk_version: "core_platform",
@@ -557,6 +535,9 @@ stubs_defaults {
include_dirs: [
"frameworks/av/aidl",
"frameworks/native/libs/permission/aidl",
+ // TODO: remove when moved to the below package
+ "frameworks/base/packages/ConnectivityT/framework-t/aidl-export",
+ "packages/modules/Connectivity/framework/aidl-export",
],
},
// These are libs from framework-internal-utils that are required (i.e. being referenced)
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index f098e10ef020..cea19451f005 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2768,7 +2768,7 @@ public class JobSchedulerService extends com.android.server.SystemService
return job.getEffectiveStandbyBucket() != RESTRICTED_INDEX
? mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS
: Math.min(mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS, 5 * MINUTE_IN_MILLIS);
- } else if (job.getEffectivePriority() == JobInfo.PRIORITY_HIGH) {
+ } else if (job.getEffectivePriority() >= JobInfo.PRIORITY_HIGH) {
return mConstants.RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS;
} else {
return mConstants.RUNTIME_MIN_GUARANTEE_MS;
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index b4edd39894f9..2c2af28c7560 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -66,8 +66,8 @@ java_library {
},
visibility: [
"//frameworks/av/apex:__subpackages__",
- "//frameworks/base", // For framework-all
"//frameworks/base/apex/media/service",
+ "//frameworks/base/api", // For framework-all
],
}
diff --git a/api/api.go b/api/api.go
index 17649e80e81a..5e5f60ee993f 100644
--- a/api/api.go
+++ b/api/api.go
@@ -27,6 +27,7 @@ import (
const art = "art.module.public.api"
const conscrypt = "conscrypt.module.public.api"
const i18n = "i18n.module.public.api"
+var core_libraries_modules = []string{art, conscrypt, i18n}
// The intention behind this soong plugin is to generate a number of "merged"
// API-related modules that would otherwise require a large amount of very
@@ -199,9 +200,28 @@ func createMergedSystemStubs(ctx android.LoadHookContext, modules []string) {
ctx.CreateModule(java.LibraryFactory, &props)
}
-func createMergedModuleLibStubs(ctx android.LoadHookContext, modules []string) {
+func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) {
+ // This module is for the "framework-all" module, which should not include the core libraries.
+ modules = removeAll(modules, core_libraries_modules)
+ // TODO(b/214988855): remove the line below when framework-bluetooth has an impl jar.
+ modules = remove(modules, "framework-bluetooth")
+ props := libraryProps{}
+ props.Name = proptools.StringPtr("all-framework-module-impl")
+ props.Static_libs = transformArray(modules, "", ".impl")
+ // Media module's impl jar is called "updatable-media"
+ for i, v := range props.Static_libs {
+ if v == "framework-media.impl" {
+ props.Static_libs[i] = "updatable-media"
+ }
+ }
+ props.Sdk_version = proptools.StringPtr("module_current")
+ props.Visibility = []string{"//frameworks/base"}
+ ctx.CreateModule(java.LibraryFactory, &props)
+}
+
+func createMergedFrameworkModuleLibStubs(ctx android.LoadHookContext, modules []string) {
// The user of this module compiles against the "core" SDK, so remove core libraries to avoid dupes.
- modules = removeAll(modules, []string{art, conscrypt, i18n})
+ modules = removeAll(modules, core_libraries_modules)
props := libraryProps{}
props.Name = proptools.StringPtr("framework-updatable-stubs-module_libs_api")
props.Static_libs = transformArray(modules, "", ".stubs.module_lib")
@@ -269,7 +289,8 @@ func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) {
createMergedPublicStubs(ctx, bootclasspath)
createMergedSystemStubs(ctx, bootclasspath)
- createMergedModuleLibStubs(ctx, bootclasspath)
+ createMergedFrameworkModuleLibStubs(ctx, bootclasspath)
+ createMergedFrameworkImpl(ctx, bootclasspath)
createMergedAnnotations(ctx, bootclasspath)
diff --git a/boot/hiddenapi/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
index 9153426b29ab..50e0a1b45c9d 100644
--- a/boot/hiddenapi/hiddenapi-max-target-o.txt
+++ b/boot/hiddenapi/hiddenapi-max-target-o.txt
@@ -35446,51 +35446,6 @@ Landroid/net/IIpConnectivityMetrics$Stub;->TRANSACTION_removeNetdEventCallback:I
Landroid/net/IIpConnectivityMetrics;->addNetdEventCallback(ILandroid/net/INetdEventCallback;)Z
Landroid/net/IIpConnectivityMetrics;->logEvent(Landroid/net/ConnectivityMetricsEvent;)I
Landroid/net/IIpConnectivityMetrics;->removeNetdEventCallback(I)Z
-Landroid/net/IIpSecService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/net/IIpSecService$Stub$Proxy;->addAddressToTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
-Landroid/net/IIpSecService$Stub$Proxy;->allocateSecurityParameterIndex(Ljava/lang/String;ILandroid/os/IBinder;)Landroid/net/IpSecSpiResponse;
-Landroid/net/IIpSecService$Stub$Proxy;->applyTransportModeTransform(Landroid/os/ParcelFileDescriptor;II)V
-Landroid/net/IIpSecService$Stub$Proxy;->applyTunnelModeTransform(IIILjava/lang/String;)V
-Landroid/net/IIpSecService$Stub$Proxy;->closeUdpEncapsulationSocket(I)V
-Landroid/net/IIpSecService$Stub$Proxy;->createTransform(Landroid/net/IpSecConfig;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTransformResponse;
-Landroid/net/IIpSecService$Stub$Proxy;->createTunnelInterface(Ljava/lang/String;Ljava/lang/String;Landroid/net/Network;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTunnelInterfaceResponse;
-Landroid/net/IIpSecService$Stub$Proxy;->deleteTransform(I)V
-Landroid/net/IIpSecService$Stub$Proxy;->deleteTunnelInterface(ILjava/lang/String;)V
-Landroid/net/IIpSecService$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
-Landroid/net/IIpSecService$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/net/IIpSecService$Stub$Proxy;->openUdpEncapsulationSocket(ILandroid/os/IBinder;)Landroid/net/IpSecUdpEncapResponse;
-Landroid/net/IIpSecService$Stub$Proxy;->releaseSecurityParameterIndex(I)V
-Landroid/net/IIpSecService$Stub$Proxy;->removeAddressFromTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
-Landroid/net/IIpSecService$Stub$Proxy;->removeTransportModeTransforms(Landroid/os/ParcelFileDescriptor;)V
-Landroid/net/IIpSecService$Stub;-><init>()V
-Landroid/net/IIpSecService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/net/IIpSecService;
-Landroid/net/IIpSecService$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/net/IIpSecService$Stub;->TRANSACTION_addAddressToTunnelInterface:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_allocateSecurityParameterIndex:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_applyTransportModeTransform:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_applyTunnelModeTransform:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_closeUdpEncapsulationSocket:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_createTransform:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_createTunnelInterface:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_deleteTransform:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_deleteTunnelInterface:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_openUdpEncapsulationSocket:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_releaseSecurityParameterIndex:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_removeAddressFromTunnelInterface:I
-Landroid/net/IIpSecService$Stub;->TRANSACTION_removeTransportModeTransforms:I
-Landroid/net/IIpSecService;->addAddressToTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
-Landroid/net/IIpSecService;->allocateSecurityParameterIndex(Ljava/lang/String;ILandroid/os/IBinder;)Landroid/net/IpSecSpiResponse;
-Landroid/net/IIpSecService;->applyTransportModeTransform(Landroid/os/ParcelFileDescriptor;II)V
-Landroid/net/IIpSecService;->applyTunnelModeTransform(IIILjava/lang/String;)V
-Landroid/net/IIpSecService;->closeUdpEncapsulationSocket(I)V
-Landroid/net/IIpSecService;->createTransform(Landroid/net/IpSecConfig;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTransformResponse;
-Landroid/net/IIpSecService;->createTunnelInterface(Ljava/lang/String;Ljava/lang/String;Landroid/net/Network;Landroid/os/IBinder;Ljava/lang/String;)Landroid/net/IpSecTunnelInterfaceResponse;
-Landroid/net/IIpSecService;->deleteTransform(I)V
-Landroid/net/IIpSecService;->deleteTunnelInterface(ILjava/lang/String;)V
-Landroid/net/IIpSecService;->openUdpEncapsulationSocket(ILandroid/os/IBinder;)Landroid/net/IpSecUdpEncapResponse;
-Landroid/net/IIpSecService;->releaseSecurityParameterIndex(I)V
-Landroid/net/IIpSecService;->removeAddressFromTunnelInterface(ILandroid/net/LinkAddress;Ljava/lang/String;)V
-Landroid/net/IIpSecService;->removeTransportModeTransforms(Landroid/os/ParcelFileDescriptor;)V
Landroid/net/INetd$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/INetd$Stub$Proxy;->addVirtualTunnelInterface(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)V
Landroid/net/INetd$Stub$Proxy;->bandwidthEnableDataSaver(Z)Z
@@ -35914,174 +35869,6 @@ Landroid/net/InterfaceConfiguration;->mFlags:Ljava/util/HashSet;
Landroid/net/InterfaceConfiguration;->mHwAddr:Ljava/lang/String;
Landroid/net/InterfaceConfiguration;->setHardwareAddress(Ljava/lang/String;)V
Landroid/net/InterfaceConfiguration;->validateFlag(Ljava/lang/String;)V
-Landroid/net/IpSecAlgorithm;->checkValidOrThrow(Ljava/lang/String;II)V
-Landroid/net/IpSecAlgorithm;->CRYPT_NULL:Ljava/lang/String;
-Landroid/net/IpSecAlgorithm;->equals(Landroid/net/IpSecAlgorithm;Landroid/net/IpSecAlgorithm;)Z
-Landroid/net/IpSecAlgorithm;->isAead()Z
-Landroid/net/IpSecAlgorithm;->isAuthentication()Z
-Landroid/net/IpSecAlgorithm;->isEncryption()Z
-Landroid/net/IpSecAlgorithm;->isUnsafeBuild()Z
-Landroid/net/IpSecAlgorithm;->mKey:[B
-Landroid/net/IpSecAlgorithm;->mName:Ljava/lang/String;
-Landroid/net/IpSecAlgorithm;->mTruncLenBits:I
-Landroid/net/IpSecAlgorithm;->TAG:Ljava/lang/String;
-Landroid/net/IpSecConfig;-><init>()V
-Landroid/net/IpSecConfig;-><init>(Landroid/net/IpSecConfig;)V
-Landroid/net/IpSecConfig;-><init>(Landroid/os/Parcel;)V
-Landroid/net/IpSecConfig;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/IpSecConfig;->equals(Landroid/net/IpSecConfig;Landroid/net/IpSecConfig;)Z
-Landroid/net/IpSecConfig;->getAuthenticatedEncryption()Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->getAuthentication()Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->getDestinationAddress()Ljava/lang/String;
-Landroid/net/IpSecConfig;->getEncapRemotePort()I
-Landroid/net/IpSecConfig;->getEncapSocketResourceId()I
-Landroid/net/IpSecConfig;->getEncapType()I
-Landroid/net/IpSecConfig;->getEncryption()Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->getMarkMask()I
-Landroid/net/IpSecConfig;->getMarkValue()I
-Landroid/net/IpSecConfig;->getMode()I
-Landroid/net/IpSecConfig;->getNattKeepaliveInterval()I
-Landroid/net/IpSecConfig;->getNetwork()Landroid/net/Network;
-Landroid/net/IpSecConfig;->getSourceAddress()Ljava/lang/String;
-Landroid/net/IpSecConfig;->getSpiResourceId()I
-Landroid/net/IpSecConfig;->mAuthenticatedEncryption:Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->mAuthentication:Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->mDestinationAddress:Ljava/lang/String;
-Landroid/net/IpSecConfig;->mEncapRemotePort:I
-Landroid/net/IpSecConfig;->mEncapSocketResourceId:I
-Landroid/net/IpSecConfig;->mEncapType:I
-Landroid/net/IpSecConfig;->mEncryption:Landroid/net/IpSecAlgorithm;
-Landroid/net/IpSecConfig;->mMarkMask:I
-Landroid/net/IpSecConfig;->mMarkValue:I
-Landroid/net/IpSecConfig;->mMode:I
-Landroid/net/IpSecConfig;->mNattKeepaliveInterval:I
-Landroid/net/IpSecConfig;->mNetwork:Landroid/net/Network;
-Landroid/net/IpSecConfig;->mSourceAddress:Ljava/lang/String;
-Landroid/net/IpSecConfig;->mSpiResourceId:I
-Landroid/net/IpSecConfig;->setAuthenticatedEncryption(Landroid/net/IpSecAlgorithm;)V
-Landroid/net/IpSecConfig;->setAuthentication(Landroid/net/IpSecAlgorithm;)V
-Landroid/net/IpSecConfig;->setDestinationAddress(Ljava/lang/String;)V
-Landroid/net/IpSecConfig;->setEncapRemotePort(I)V
-Landroid/net/IpSecConfig;->setEncapSocketResourceId(I)V
-Landroid/net/IpSecConfig;->setEncapType(I)V
-Landroid/net/IpSecConfig;->setEncryption(Landroid/net/IpSecAlgorithm;)V
-Landroid/net/IpSecConfig;->setMarkMask(I)V
-Landroid/net/IpSecConfig;->setMarkValue(I)V
-Landroid/net/IpSecConfig;->setMode(I)V
-Landroid/net/IpSecConfig;->setNattKeepaliveInterval(I)V
-Landroid/net/IpSecConfig;->setNetwork(Landroid/net/Network;)V
-Landroid/net/IpSecConfig;->setSourceAddress(Ljava/lang/String;)V
-Landroid/net/IpSecConfig;->setSpiResourceId(I)V
-Landroid/net/IpSecConfig;->TAG:Ljava/lang/String;
-Landroid/net/IpSecManager$IpSecTunnelInterface;-><init>(Landroid/content/Context;Landroid/net/IIpSecService;Ljava/net/InetAddress;Ljava/net/InetAddress;Landroid/net/Network;)V
-Landroid/net/IpSecManager$IpSecTunnelInterface;->addAddress(Ljava/net/InetAddress;I)V
-Landroid/net/IpSecManager$IpSecTunnelInterface;->getInterfaceName()Ljava/lang/String;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->getResourceId()I
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mCloseGuard:Ldalvik/system/CloseGuard;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mInterfaceName:Ljava/lang/String;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mLocalAddress:Ljava/net/InetAddress;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mOpPackageName:Ljava/lang/String;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mRemoteAddress:Ljava/net/InetAddress;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mResourceId:I
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mService:Landroid/net/IIpSecService;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->mUnderlyingNetwork:Landroid/net/Network;
-Landroid/net/IpSecManager$IpSecTunnelInterface;->removeAddress(Ljava/net/InetAddress;I)V
-Landroid/net/IpSecManager$ResourceUnavailableException;-><init>(Ljava/lang/String;)V
-Landroid/net/IpSecManager$SecurityParameterIndex;-><init>(Landroid/net/IIpSecService;Ljava/net/InetAddress;I)V
-Landroid/net/IpSecManager$SecurityParameterIndex;->getResourceId()I
-Landroid/net/IpSecManager$SecurityParameterIndex;->mCloseGuard:Ldalvik/system/CloseGuard;
-Landroid/net/IpSecManager$SecurityParameterIndex;->mDestinationAddress:Ljava/net/InetAddress;
-Landroid/net/IpSecManager$SecurityParameterIndex;->mResourceId:I
-Landroid/net/IpSecManager$SecurityParameterIndex;->mService:Landroid/net/IIpSecService;
-Landroid/net/IpSecManager$SecurityParameterIndex;->mSpi:I
-Landroid/net/IpSecManager$SpiUnavailableException;-><init>(Ljava/lang/String;I)V
-Landroid/net/IpSecManager$SpiUnavailableException;->mSpi:I
-Landroid/net/IpSecManager$Status;->OK:I
-Landroid/net/IpSecManager$Status;->RESOURCE_UNAVAILABLE:I
-Landroid/net/IpSecManager$Status;->SPI_UNAVAILABLE:I
-Landroid/net/IpSecManager$UdpEncapsulationSocket;-><init>(Landroid/net/IIpSecService;I)V
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->getResourceId()I
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->mCloseGuard:Ldalvik/system/CloseGuard;
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->mPfd:Landroid/os/ParcelFileDescriptor;
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->mPort:I
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->mResourceId:I
-Landroid/net/IpSecManager$UdpEncapsulationSocket;->mService:Landroid/net/IIpSecService;
-Landroid/net/IpSecManager;-><init>(Landroid/content/Context;Landroid/net/IIpSecService;)V
-Landroid/net/IpSecManager;->applyTunnelModeTransform(Landroid/net/IpSecManager$IpSecTunnelInterface;ILandroid/net/IpSecTransform;)V
-Landroid/net/IpSecManager;->createIpSecTunnelInterface(Ljava/net/InetAddress;Ljava/net/InetAddress;Landroid/net/Network;)Landroid/net/IpSecManager$IpSecTunnelInterface;
-Landroid/net/IpSecManager;->INVALID_RESOURCE_ID:I
-Landroid/net/IpSecManager;->maybeHandleServiceSpecificException(Landroid/os/ServiceSpecificException;)V
-Landroid/net/IpSecManager;->mContext:Landroid/content/Context;
-Landroid/net/IpSecManager;->mService:Landroid/net/IIpSecService;
-Landroid/net/IpSecManager;->removeTunnelModeTransform(Landroid/net/Network;Landroid/net/IpSecTransform;)V
-Landroid/net/IpSecManager;->rethrowCheckedExceptionFromServiceSpecificException(Landroid/os/ServiceSpecificException;)Ljava/io/IOException;
-Landroid/net/IpSecManager;->rethrowUncheckedExceptionFromServiceSpecificException(Landroid/os/ServiceSpecificException;)Ljava/lang/RuntimeException;
-Landroid/net/IpSecManager;->TAG:Ljava/lang/String;
-Landroid/net/IpSecSpiResponse;-><init>(I)V
-Landroid/net/IpSecSpiResponse;-><init>(III)V
-Landroid/net/IpSecSpiResponse;-><init>(Landroid/os/Parcel;)V
-Landroid/net/IpSecSpiResponse;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/IpSecSpiResponse;->resourceId:I
-Landroid/net/IpSecSpiResponse;->spi:I
-Landroid/net/IpSecSpiResponse;->status:I
-Landroid/net/IpSecSpiResponse;->TAG:Ljava/lang/String;
-Landroid/net/IpSecTransform$Builder;->buildTunnelModeTransform(Ljava/net/InetAddress;Landroid/net/IpSecManager$SecurityParameterIndex;)Landroid/net/IpSecTransform;
-Landroid/net/IpSecTransform$Builder;->mConfig:Landroid/net/IpSecConfig;
-Landroid/net/IpSecTransform$Builder;->mContext:Landroid/content/Context;
-Landroid/net/IpSecTransform$NattKeepaliveCallback;-><init>()V
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_HARDWARE_ERROR:I
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_HARDWARE_UNSUPPORTED:I
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->ERROR_INVALID_NETWORK:I
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->onError(I)V
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->onStarted()V
-Landroid/net/IpSecTransform$NattKeepaliveCallback;->onStopped()V
-Landroid/net/IpSecTransform;-><init>(Landroid/content/Context;Landroid/net/IpSecConfig;)V
-Landroid/net/IpSecTransform;->activate()Landroid/net/IpSecTransform;
-Landroid/net/IpSecTransform;->checkResultStatus(I)V
-Landroid/net/IpSecTransform;->ENCAP_ESPINUDP:I
-Landroid/net/IpSecTransform;->ENCAP_ESPINUDP_NON_IKE:I
-Landroid/net/IpSecTransform;->ENCAP_NONE:I
-Landroid/net/IpSecTransform;->equals(Landroid/net/IpSecTransform;Landroid/net/IpSecTransform;)Z
-Landroid/net/IpSecTransform;->getConfig()Landroid/net/IpSecConfig;
-Landroid/net/IpSecTransform;->getIpSecService()Landroid/net/IIpSecService;
-Landroid/net/IpSecTransform;->getResourceId()I
-Landroid/net/IpSecTransform;->mCallbackHandler:Landroid/os/Handler;
-Landroid/net/IpSecTransform;->mCloseGuard:Ldalvik/system/CloseGuard;
-Landroid/net/IpSecTransform;->mConfig:Landroid/net/IpSecConfig;
-Landroid/net/IpSecTransform;->mContext:Landroid/content/Context;
-Landroid/net/IpSecTransform;->mKeepalive:Landroid/net/ConnectivityManager$PacketKeepalive;
-Landroid/net/IpSecTransform;->mKeepaliveCallback:Landroid/net/ConnectivityManager$PacketKeepaliveCallback;
-Landroid/net/IpSecTransform;->MODE_TRANSPORT:I
-Landroid/net/IpSecTransform;->MODE_TUNNEL:I
-Landroid/net/IpSecTransform;->mResourceId:I
-Landroid/net/IpSecTransform;->mUserKeepaliveCallback:Landroid/net/IpSecTransform$NattKeepaliveCallback;
-Landroid/net/IpSecTransform;->startNattKeepalive(Landroid/net/IpSecTransform$NattKeepaliveCallback;ILandroid/os/Handler;)V
-Landroid/net/IpSecTransform;->stopNattKeepalive()V
-Landroid/net/IpSecTransform;->TAG:Ljava/lang/String;
-Landroid/net/IpSecTransformResponse;-><init>(I)V
-Landroid/net/IpSecTransformResponse;-><init>(II)V
-Landroid/net/IpSecTransformResponse;-><init>(Landroid/os/Parcel;)V
-Landroid/net/IpSecTransformResponse;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/IpSecTransformResponse;->resourceId:I
-Landroid/net/IpSecTransformResponse;->status:I
-Landroid/net/IpSecTransformResponse;->TAG:Ljava/lang/String;
-Landroid/net/IpSecTunnelInterfaceResponse;-><init>(I)V
-Landroid/net/IpSecTunnelInterfaceResponse;-><init>(IILjava/lang/String;)V
-Landroid/net/IpSecTunnelInterfaceResponse;-><init>(Landroid/os/Parcel;)V
-Landroid/net/IpSecTunnelInterfaceResponse;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/IpSecTunnelInterfaceResponse;->interfaceName:Ljava/lang/String;
-Landroid/net/IpSecTunnelInterfaceResponse;->resourceId:I
-Landroid/net/IpSecTunnelInterfaceResponse;->status:I
-Landroid/net/IpSecTunnelInterfaceResponse;->TAG:Ljava/lang/String;
-Landroid/net/IpSecUdpEncapResponse;-><init>(I)V
-Landroid/net/IpSecUdpEncapResponse;-><init>(IIILjava/io/FileDescriptor;)V
-Landroid/net/IpSecUdpEncapResponse;-><init>(Landroid/os/Parcel;)V
-Landroid/net/IpSecUdpEncapResponse;->CREATOR:Landroid/os/Parcelable$Creator;
-Landroid/net/IpSecUdpEncapResponse;->fileDescriptor:Landroid/os/ParcelFileDescriptor;
-Landroid/net/IpSecUdpEncapResponse;->port:I
-Landroid/net/IpSecUdpEncapResponse;->resourceId:I
-Landroid/net/IpSecUdpEncapResponse;->status:I
-Landroid/net/IpSecUdpEncapResponse;->TAG:Ljava/lang/String;
Landroid/net/ITetheringStatsProvider$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/net/ITetheringStatsProvider$Stub$Proxy;->getInterfaceDescriptor()Ljava/lang/String;
Landroid/net/ITetheringStatsProvider$Stub$Proxy;->getTetherStats(I)Landroid/net/NetworkStats;
diff --git a/core/api/current.txt b/core/api/current.txt
index fe8b979a55e5..da14dfeec5c8 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -3074,6 +3074,7 @@ package android.accessibilityservice {
method public void onSystemActionsChanged();
method public final boolean performGlobalAction(int);
method public void setAccessibilityFocusAppearance(int, @ColorInt int);
+ method public void setAnimationScale(float);
method public boolean setCacheEnabled(boolean);
method public void setGestureDetectionPassthroughRegion(int, @NonNull android.graphics.Region);
method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
@@ -4069,7 +4070,7 @@ package android.app {
method public int getMaxNumPictureInPictureActions();
method public final android.media.session.MediaController getMediaController();
method @NonNull public android.view.MenuInflater getMenuInflater();
- method @Nullable public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
+ method @NonNull public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
method public final android.app.Activity getParent();
method @Nullable public android.content.Intent getParentActivityIntent();
method public android.content.SharedPreferences getPreferences(int);
@@ -4875,6 +4876,7 @@ package android.app {
field public static final int REASON_DEPENDENCY_DIED = 12; // 0xc
field public static final int REASON_EXCESSIVE_RESOURCE_USAGE = 9; // 0x9
field public static final int REASON_EXIT_SELF = 1; // 0x1
+ field public static final int REASON_FREEZER = 14; // 0xe
field public static final int REASON_INITIALIZATION_FAILURE = 7; // 0x7
field public static final int REASON_LOW_MEMORY = 3; // 0x3
field public static final int REASON_OTHER = 13; // 0xd
@@ -4970,7 +4972,7 @@ package android.app {
method @NonNull @UiContext public final android.content.Context getContext();
method @Nullable public android.view.View getCurrentFocus();
method @NonNull public android.view.LayoutInflater getLayoutInflater();
- method @Nullable public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
+ method @NonNull public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
method @Nullable public final android.app.Activity getOwnerActivity();
method @Nullable public final android.view.SearchEvent getSearchEvent();
method public final int getVolumeControlStream();
@@ -6949,6 +6951,7 @@ package android.app {
method public boolean performGlobalAction(int);
method public void revokeRuntimePermission(String, String);
method public void revokeRuntimePermissionAsUser(String, String, android.os.UserHandle);
+ method public void setAnimationScale(float);
method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener);
method public boolean setRotation(int);
method public void setRunAsMonkey(boolean);
@@ -7611,7 +7614,7 @@ package android.app.admin {
field public static final String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
field public static final String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
field public static final String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
- field public static final String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
+ field @Deprecated public static final String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
field @Deprecated public static final String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
field public static final String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";
field public static final String EXTRA_PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT = "android.app.extra.PROVISIONING_SENSORS_PERMISSION_GRANT_OPT_OUT";
@@ -9824,7 +9827,6 @@ package android.content {
field public static final String STATUS_BAR_SERVICE = "statusbar";
field public static final String STORAGE_SERVICE = "storage";
field public static final String STORAGE_STATS_SERVICE = "storagestats";
- field public static final String SUPPLEMENTAL_PROCESS_SERVICE = "supplemental_process";
field public static final String SYSTEM_HEALTH_SERVICE = "systemhealth";
field public static final String TELECOM_SERVICE = "telecom";
field public static final String TELEPHONY_IMS_SERVICE = "telephony_ims";
@@ -19677,10 +19679,13 @@ package android.media {
method public android.media.AudioAttributes.Builder setUsage(int);
}
- public class AudioDescriptor {
+ public class AudioDescriptor implements android.os.Parcelable {
+ method public int describeContents();
method @NonNull public byte[] getDescriptor();
method public int getEncapsulationType();
method public int getStandard();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioDescriptor> CREATOR;
field public static final int STANDARD_EDID = 1; // 0x1
field public static final int STANDARD_NONE = 0; // 0x0
}
@@ -20196,14 +20201,17 @@ package android.media {
method @NonNull public android.media.AudioPresentation.Builder setProgramId(int);
}
- public class AudioProfile {
+ public class AudioProfile implements android.os.Parcelable {
+ method public int describeContents();
method @NonNull public int[] getChannelIndexMasks();
method @NonNull public int[] getChannelMasks();
method public int getEncapsulationType();
method public int getFormat();
method @NonNull public int[] getSampleRates();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int AUDIO_ENCAPSULATION_TYPE_IEC61937 = 1; // 0x1
field public static final int AUDIO_ENCAPSULATION_TYPE_NONE = 0; // 0x0
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.AudioProfile> CREATOR;
}
public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection {
@@ -26392,75 +26400,6 @@ package android.net {
method @NonNull public android.net.Ikev2VpnProfile.Builder setProxy(@Nullable android.net.ProxyInfo);
}
- public final class IpSecAlgorithm implements android.os.Parcelable {
- ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[]);
- ctor public IpSecAlgorithm(@NonNull String, @NonNull byte[], int);
- method public int describeContents();
- method @NonNull public byte[] getKey();
- method @NonNull public String getName();
- method @NonNull public static java.util.Set<java.lang.String> getSupportedAlgorithms();
- method public int getTruncationLengthBits();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final String AUTH_AES_CMAC = "cmac(aes)";
- field public static final String AUTH_AES_XCBC = "xcbc(aes)";
- field public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))";
- field public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)";
- field public static final String AUTH_HMAC_MD5 = "hmac(md5)";
- field public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
- field public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
- field public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
- field public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
- field @NonNull public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
- field public static final String CRYPT_AES_CBC = "cbc(aes)";
- field public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))";
- }
-
- public final class IpSecManager {
- method @NonNull public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(@NonNull java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
- method @NonNull public android.net.IpSecManager.SecurityParameterIndex allocateSecurityParameterIndex(@NonNull java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- method public void applyTransportModeTransform(@NonNull java.net.Socket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
- method public void applyTransportModeTransform(@NonNull java.net.DatagramSocket, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
- method public void applyTransportModeTransform(@NonNull java.io.FileDescriptor, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
- method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
- method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
- method public void removeTransportModeTransforms(@NonNull java.net.Socket) throws java.io.IOException;
- method public void removeTransportModeTransforms(@NonNull java.net.DatagramSocket) throws java.io.IOException;
- method public void removeTransportModeTransforms(@NonNull java.io.FileDescriptor) throws java.io.IOException;
- field public static final int DIRECTION_IN = 0; // 0x0
- field public static final int DIRECTION_OUT = 1; // 0x1
- }
-
- public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
- }
-
- public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
- method public void close();
- method public int getSpi();
- }
-
- public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
- method public int getSpi();
- }
-
- public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
- method public void close() throws java.io.IOException;
- method public java.io.FileDescriptor getFileDescriptor();
- method public int getPort();
- }
-
- public final class IpSecTransform implements java.lang.AutoCloseable {
- method public void close();
- }
-
- public static class IpSecTransform.Builder {
- ctor public IpSecTransform.Builder(@NonNull android.content.Context);
- method @NonNull public android.net.IpSecTransform buildTransportModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- method @NonNull public android.net.IpSecTransform.Builder setAuthenticatedEncryption(@NonNull android.net.IpSecAlgorithm);
- method @NonNull public android.net.IpSecTransform.Builder setAuthentication(@NonNull android.net.IpSecAlgorithm);
- method @NonNull public android.net.IpSecTransform.Builder setEncryption(@NonNull android.net.IpSecAlgorithm);
- method @NonNull public android.net.IpSecTransform.Builder setIpv4Encapsulation(@NonNull android.net.IpSecManager.UdpEncapsulationSocket, int);
- }
-
public class LocalServerSocket implements java.io.Closeable {
ctor public LocalServerSocket(String) throws java.io.IOException;
ctor public LocalServerSocket(java.io.FileDescriptor) throws java.io.IOException;
@@ -43010,6 +42949,7 @@ package android.telephony {
field public static final int ENCODING_16BIT = 3; // 0x3
field public static final int ENCODING_7BIT = 1; // 0x1
field public static final int ENCODING_8BIT = 2; // 0x2
+ field public static final int ENCODING_KSC5601 = 4; // 0x4
field public static final int ENCODING_UNKNOWN = 0; // 0x0
field public static final String FORMAT_3GPP = "3gpp";
field public static final String FORMAT_3GPP2 = "3gpp2";
@@ -48973,7 +48913,7 @@ package android.view {
}
public interface OnBackInvokedDispatcherOwner {
- method @Nullable public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
+ method @NonNull public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
}
public interface OnReceiveContentListener {
@@ -49401,7 +49341,7 @@ package android.view {
field @NonNull public static final android.os.Parcelable.Creator<android.view.VerifiedMotionEvent> CREATOR;
}
- @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback android.view.OnBackInvokedDispatcherOwner {
+ @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
ctor public View(android.content.Context);
ctor public View(android.content.Context, @Nullable android.util.AttributeSet);
ctor public View(android.content.Context, @Nullable android.util.AttributeSet, int);
@@ -49605,7 +49545,6 @@ package android.view {
method @IdRes public int getNextFocusLeftId();
method @IdRes public int getNextFocusRightId();
method @IdRes public int getNextFocusUpId();
- method @Nullable public android.view.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
method @ColorInt public int getOutlineAmbientShadowColor();
method public android.view.ViewOutlineProvider getOutlineProvider();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index 6e7bc765c157..9737cde48b4d 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -139,9 +139,14 @@ package android.content {
package android.content.pm {
+ public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
+ method @NonNull public java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraryInfos();
+ }
+
public abstract class PackageManager {
method @NonNull public String getPermissionControllerPackageName();
method @NonNull public String getSupplementalProcessPackageName();
+ field public static final int MATCH_STATIC_SHARED_AND_SDK_LIBRARIES = 67108864; // 0x4000000
}
}
@@ -192,7 +197,7 @@ package android.media {
method public void adjustSuggestedStreamVolumeForUid(int, int, int, @NonNull String, int, int, int);
method @NonNull public java.util.List<android.bluetooth.BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp();
method @NonNull public java.util.List<android.bluetooth.BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio();
- method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BtProfileConnectionInfo);
+ method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void handleBluetoothActiveDeviceChanged(@Nullable android.bluetooth.BluetoothDevice, @Nullable android.bluetooth.BluetoothDevice, @NonNull android.media.BluetoothProfileConnectionInfo);
method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setA2dpSuspended(boolean);
method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setBluetoothHeadsetProperties(@NonNull String, boolean, boolean);
method @RequiresPermission("android.permission.BLUETOOTH_STACK") public void setHfpEnabled(boolean);
@@ -202,18 +207,18 @@ package android.media {
field public static final int FLAG_FROM_KEY = 4096; // 0x1000
}
- public final class BtProfileConnectionInfo implements android.os.Parcelable {
- method @NonNull public static android.media.BtProfileConnectionInfo a2dpInfo(boolean, int);
- method @NonNull public static android.media.BtProfileConnectionInfo a2dpSinkInfo(int);
+ public final class BluetoothProfileConnectionInfo implements android.os.Parcelable {
+ method @NonNull public static android.media.BluetoothProfileConnectionInfo createA2dpInfo(boolean, int);
+ method @NonNull public static android.media.BluetoothProfileConnectionInfo createA2dpSinkInfo(int);
+ method @NonNull public static android.media.BluetoothProfileConnectionInfo createHearingAidInfo(boolean);
+ method @NonNull public static android.media.BluetoothProfileConnectionInfo createLeAudioInfo(boolean, boolean);
method public int describeContents();
- method public boolean getIsLeOutput();
method public int getProfile();
- method public boolean getSuppressNoisyIntent();
method public int getVolume();
- method @NonNull public static android.media.BtProfileConnectionInfo hearingAidInfo(boolean);
- method @NonNull public static android.media.BtProfileConnectionInfo leAudio(boolean, boolean);
+ method public boolean isLeOutput();
+ method public boolean isSuppressNoisyIntent();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.media.BtProfileConnectionInfo> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.media.BluetoothProfileConnectionInfo> CREATOR;
}
public class MediaMetadataRetriever implements java.lang.AutoCloseable {
@@ -278,14 +283,6 @@ package android.net {
field @NonNull public static final android.os.Parcelable.Creator<android.net.EthernetNetworkSpecifier> CREATOR;
}
- public final class IpSecManager {
- field public static final int DIRECTION_FWD = 2; // 0x2
- }
-
- public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
- method public int getResourceId();
- }
-
public class LocalSocket implements java.io.Closeable {
ctor public LocalSocket(@NonNull java.io.FileDescriptor);
}
diff --git a/core/api/removed.txt b/core/api/removed.txt
index 311b110f1997..07639fbf5378 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -513,7 +513,7 @@ package android.util {
package android.view {
- @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback android.view.OnBackInvokedDispatcherOwner {
+ @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
method protected void initializeFadingEdge(android.content.res.TypedArray);
method protected void initializeScrollbars(android.content.res.TypedArray);
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 1cba58c391dc..a97ccc91d1ff 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -166,6 +166,7 @@ package android {
field public static final String MANAGE_CONTENT_SUGGESTIONS = "android.permission.MANAGE_CONTENT_SUGGESTIONS";
field public static final String MANAGE_DEBUGGING = "android.permission.MANAGE_DEBUGGING";
field public static final String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
+ field public static final String MANAGE_ETHERNET_NETWORKS = "android.permission.MANAGE_ETHERNET_NETWORKS";
field public static final String MANAGE_FACTORY_RESET_PROTECTION = "android.permission.MANAGE_FACTORY_RESET_PROTECTION";
field public static final String MANAGE_GAME_ACTIVITY = "android.permission.MANAGE_GAME_ACTIVITY";
field public static final String MANAGE_GAME_MODE = "android.permission.MANAGE_GAME_MODE";
@@ -1084,6 +1085,7 @@ package android.app.admin {
method public boolean isDeviceManaged();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public boolean isDpcDownloaded();
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isManagedKiosk();
method public boolean isSecondaryLockscreenEnabled(@NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS}) public boolean isUnattendedManagedKiosk();
@@ -1096,6 +1098,7 @@ package android.app.admin {
method @RequiresPermission(android.Manifest.permission.SEND_LOST_MODE_LOCATION_UPDATES) public void sendLostModeLocationUpdate(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setDpcDownloaded(boolean);
method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setDrawables(@NonNull java.util.Set<android.app.admin.DevicePolicyDrawableResource>);
method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
@@ -1174,6 +1177,13 @@ package android.app.admin {
field public static final String UNDEFINED = "UNDEFINED";
}
+ public static final class DevicePolicyResources.Strings.Dialer {
+ field public static final String NOTIFICATION_INCOMING_WORK_CALL_TITLE = "Dialer.NOTIFICATION_INCOMING_WORK_CALL_TITLE";
+ field public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE = "Dialer.NOTIFICATION_MISSED_WORK_CALL_TITLE";
+ field public static final String NOTIFICATION_ONGOING_WORK_CALL_TITLE = "Dialer.NOTIFICATION_ONGOING_WORK_CALL_TITLE";
+ field public static final String NOTIFICATION_WIFI_WORK_CALL_LABEL = "Dialer.NOTIFICATION_WIFI_WORK_CALL_LABEL";
+ }
+
public static final class DevicePolicyResources.Strings.DocumentsUi {
field public static final String CANT_SAVE_TO_PERSONAL_MESSAGE = "DocumentsUi.CANT_SAVE_TO_PERSONAL_MESSAGE";
field public static final String CANT_SAVE_TO_PERSONAL_TITLE = "DocumentsUi.CANT_SAVE_TO_PERSONAL_TITLE";
@@ -2826,8 +2836,8 @@ package android.content {
field public static final String APP_PREDICTION_SERVICE = "app_prediction";
field public static final String BACKUP_SERVICE = "backup";
field public static final String BATTERY_STATS_SERVICE = "batterystats";
- field @Deprecated public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
- field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
+ field public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
+ field @Deprecated public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
field public static final String CLOUDSEARCH_SERVICE = "cloudsearch";
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
field public static final String CONTEXTHUB_SERVICE = "contexthub";
@@ -5925,11 +5935,20 @@ package android.media {
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.AudioAttributes.Builder setSystemUsage(int);
}
+ public class AudioDescriptor implements android.os.Parcelable {
+ ctor public AudioDescriptor(int, int, @NonNull byte[]);
+ }
+
public final class AudioDeviceAttributes implements android.os.Parcelable {
ctor public AudioDeviceAttributes(@NonNull android.media.AudioDeviceInfo);
ctor public AudioDeviceAttributes(int, int, @NonNull String);
+ ctor public AudioDeviceAttributes(int, int, @NonNull String, @NonNull String, @NonNull java.util.List<android.media.AudioProfile>, @NonNull java.util.List<android.media.AudioDescriptor>);
method public int describeContents();
+ method public boolean equalTypeAddress(@Nullable Object);
method @NonNull public String getAddress();
+ method @NonNull public java.util.List<android.media.AudioDescriptor> getAudioDescriptors();
+ method @NonNull public java.util.List<android.media.AudioProfile> getAudioProfiles();
+ method @NonNull public String getName();
method public int getRole();
method public int getType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -6086,6 +6105,10 @@ package android.media {
field public static final int PLAYER_TYPE_UNKNOWN = -1; // 0xffffffff
}
+ public class AudioProfile implements android.os.Parcelable {
+ ctor public AudioProfile(int, @NonNull int[], @NonNull int[], @NonNull int[], int);
+ }
+
public class AudioRecord implements android.media.AudioRecordingMonitor android.media.AudioRouting android.media.MicrophoneDirection {
ctor @RequiresPermission(android.Manifest.permission.RECORD_AUDIO) public AudioRecord(android.media.AudioAttributes, android.media.AudioFormat, int, int) throws java.lang.IllegalArgumentException;
method public static long getMaxSharedAudioHistoryMillis();
@@ -7952,7 +7975,7 @@ package android.media.tv.tuner.frontend {
public class FrontendStatus {
method public int getAgc();
- method @NonNull public android.media.tv.tuner.frontend.Atsc3PlpInfo[] getAllAtsc3PlpInfo();
+ method @NonNull public java.util.List<android.media.tv.tuner.frontend.Atsc3PlpInfo> getAllAtsc3PlpInfo();
method @NonNull public android.media.tv.tuner.frontend.FrontendStatus.Atsc3PlpTuningInfo[] getAtsc3PlpTuningInfo();
method public int getBandwidth();
method public int getBer();
@@ -8336,23 +8359,6 @@ package android.net {
method public void release();
}
- public final class IpSecManager {
- method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull android.net.IpSecManager.IpSecTunnelInterface, int, @NonNull android.net.IpSecTransform) throws java.io.IOException;
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecManager.IpSecTunnelInterface createIpSecTunnelInterface(@NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull android.net.Network) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
- }
-
- public static final class IpSecManager.IpSecTunnelInterface implements java.lang.AutoCloseable {
- method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
- method public void close();
- method @NonNull public String getInterfaceName();
- method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
- method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void setUnderlyingNetwork(@NonNull android.net.Network) throws java.io.IOException;
- }
-
- public static class IpSecTransform.Builder {
- method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public android.net.IpSecTransform buildTunnelModeTransform(@NonNull java.net.InetAddress, @NonNull android.net.IpSecManager.SecurityParameterIndex) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- }
-
public final class MatchAllNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
ctor public MatchAllNetworkSpecifier();
method public int describeContents();
@@ -9964,7 +9970,8 @@ package android.permission {
method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, long, int, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
field @RequiresPermission(android.Manifest.permission.START_REVIEW_PERMISSION_DECISIONS) public static final String ACTION_REVIEW_PERMISSION_DECISIONS = "android.permission.action.REVIEW_PERMISSION_DECISIONS";
field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -11214,6 +11221,7 @@ package android.service.games {
method public void onTransientSystemBarVisibilityFromRevealGestureChanged(boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final boolean restartGame();
method public void setTaskOverlayView(@NonNull android.view.View, @NonNull android.view.ViewGroup.LayoutParams);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY) public final void startActivityFromGameSessionForResult(@NonNull android.content.Intent, @Nullable android.os.Bundle, @NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSessionActivityCallback);
method public void takeScreenshot(@NonNull java.util.concurrent.Executor, @NonNull android.service.games.GameSession.ScreenshotCallback);
}
@@ -11223,6 +11231,11 @@ package android.service.games {
field public static final int ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR = 0; // 0x0
}
+ public interface GameSessionActivityCallback {
+ method public void onActivityResult(int, @Nullable android.content.Intent);
+ method public default void onActivityStartFailed(@NonNull Throwable);
+ }
+
public abstract class GameSessionService extends android.app.Service {
ctor public GameSessionService();
method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
@@ -12251,6 +12264,7 @@ package android.telecom {
field public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; // 0x2
field public static final int CALL_SOURCE_UNSPECIFIED = 0; // 0x0
field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
+ field public static final String EXTRA_CALL_HAS_IN_BAND_RINGTONE = "android.telecom.extra.CALL_HAS_IN_BAND_RINGTONE";
field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
@@ -14734,6 +14748,7 @@ package android.telephony.ims {
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.RcsClientConfiguration> CREATOR;
field public static final String RCS_PROFILE_1_0 = "UP_1.0";
field public static final String RCS_PROFILE_2_3 = "UP_2.3";
+ field public static final String RCS_PROFILE_2_4 = "UP_2.4";
}
public final class RcsContactPresenceTuple implements android.os.Parcelable {
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index e17a9bb1512c..1b45e88584fe 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -1,11 +1,5 @@
// Baseline format: 1.0
ArrayReturn: android.view.contentcapture.ViewNode#getAutofillOptions():
-
-
-
-BuilderSetStyle: android.net.IpSecTransform.Builder#buildTunnelModeTransform(java.net.InetAddress, android.net.IpSecManager.SecurityParameterIndex):
- Builder methods names should use setFoo() / addFoo() / clearFoo() style: method android.net.IpSecTransform.Builder.buildTunnelModeTransform(java.net.InetAddress,android.net.IpSecManager.SecurityParameterIndex)
-
ExecutorRegistration: android.media.MediaPlayer#setOnRtpRxNoticeListener(android.content.Context, android.media.MediaPlayer.OnRtpRxNoticeListener, android.os.Handler):
Registration methods should have overload that accepts delivery Executor: `setOnRtpRxNoticeListener`
@@ -15,8 +9,6 @@ GenericException: android.app.prediction.AppPredictor#finalize():
GenericException: android.hardware.location.ContextHubClient#finalize():
-GenericException: android.net.IpSecManager.IpSecTunnelInterface#finalize():
-
GenericException: android.service.autofill.augmented.FillWindow#finalize():
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index fea739668512..9d6fc0e67f03 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1607,10 +1607,6 @@ package android.net {
method public void setIncludeTestInterfaces(boolean);
}
- public final class IpSecManager {
- field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
- }
-
public class NetworkPolicyManager {
method public boolean getRestrictBackground();
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
@@ -2820,7 +2816,7 @@ package android.view {
method public void setView(@NonNull android.view.View, @NonNull android.view.WindowManager.LayoutParams);
}
- @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback android.view.OnBackInvokedDispatcherOwner {
+ @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
method public android.view.View getTooltipView();
method public boolean isAutofilled();
method public static boolean isDefaultFocusHighlightEnabled();
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 5649c5f1f7db..edf9ece4661c 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -176,6 +176,18 @@ filegroup {
"com/android/internal/util/IndentingPrintWriter.java",
"com/android/internal/util/MessageUtils.java",
"com/android/internal/util/WakeupMessage.java",
+ // TODO: delete as soon as NetworkStatsFactory stops using
+ "com/android/internal/util/ProcFileReader.java",
+ ],
+}
+
+// keep these files in sync with the packages/modules/Connectivity jarjar-rules.txt for
+// the connectivity module.
+filegroup {
+ name: "framework-connectivity-api-shared-srcs",
+ srcs: [
+ "android/util/IndentingPrintWriter.java",
+ "com/android/internal/util/FileRotator.java",
],
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 42d2d28ae928..50473f1d8c84 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -3120,6 +3120,33 @@ public abstract class AccessibilityService extends Service {
}
}
+ /**
+ * Sets the system settings values that control the scaling factor for animations. The scale
+ * controls the animation playback speed for animations that respect these settings. Animations
+ * that do not respect the settings values will not be affected by this function. A lower scale
+ * value results in a faster speed. A value of <code>0</code> disables animations entirely. When
+ * animations are disabled services receive window change events more quickly which can reduce
+ * the potential by confusion by reducing the time during which windows are in transition.
+ *
+ * @see AccessibilityEvent#TYPE_WINDOWS_CHANGED
+ * @see AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
+ * @see android.provider.Settings.Global#WINDOW_ANIMATION_SCALE
+ * @see android.provider.Settings.Global#TRANSITION_ANIMATION_SCALE
+ * @see android.provider.Settings.Global#ANIMATOR_DURATION_SCALE
+ * @param scale The scaling factor for all animations.
+ */
+ public void setAnimationScale(float scale) {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance(this).getConnection(mConnectionId);
+ if (connection != null) {
+ try {
+ connection.setAnimationScale(scale);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
private static class AccessibilityContext extends ContextWrapper {
private final int mConnectionId;
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index 2cc15b40106b..0d6b19941afe 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -144,4 +144,6 @@ interface IAccessibilityServiceConnection {
void onDoubleTap(int displayId);
void onDoubleTapAndHold(int displayId);
+
+ void setAnimationScale(float scale);
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 530666b8f1d7..8935022639e4 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5503,6 +5503,17 @@ public class Activity extends ContextThemeWrapper
*/
public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
IBinder permissionToken, boolean ignoreTargetSecurity, int userId) {
+ startActivityAsCaller(intent, options, permissionToken, ignoreTargetSecurity, userId, -1);
+ }
+
+ /**
+ * @see #startActivityAsCaller(Intent, Bundle, IBinder, boolean, int)
+ * @param requestCode The request code used for returning a result or -1 if no result should be
+ * returned.
+ * @hide
+ */
+ public void startActivityAsCaller(Intent intent, @Nullable Bundle options,
+ IBinder permissionToken, boolean ignoreTargetSecurity, int userId, int requestCode) {
if (mParent != null) {
throw new RuntimeException("Can't be called from a child");
}
@@ -5510,11 +5521,11 @@ public class Activity extends ContextThemeWrapper
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivityAsCaller(
this, mMainThread.getApplicationThread(), mToken, this,
- intent, -1, options, permissionToken, ignoreTargetSecurity, userId);
+ intent, requestCode, options, permissionToken, ignoreTargetSecurity,
+ userId);
if (ar != null) {
mMainThread.sendActivityResult(
- mToken, mEmbeddedID, -1, ar.getResultCode(),
- ar.getResultData());
+ mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
}
cancelInputsAndStartExitTransition(options);
}
@@ -6139,6 +6150,10 @@ public class Activity extends ContextThemeWrapper
* you to specify a custom animation even when starting an activity from
* outside the context of the current top activity.
*
+ * <p>Af of {@link android.os.Build.VERSION_CODES#S} application can only specify
+ * a transition animation when the transition happens within the same task. System
+ * default animation is used for cross-task transition animations.
+ *
* @param enterAnim A resource ID of the animation resource to use for
* the incoming activity. Use 0 for no animation.
* @param exitAnim A resource ID of the animation resource to use for
@@ -8742,17 +8757,15 @@ public class Activity extends ContextThemeWrapper
* Returns the {@link OnBackInvokedDispatcher} instance associated with the window that this
* activity is attached to.
*
- * Returns null if the activity is not attached to a window with a decor.
+ * @throws IllegalStateException if this Activity is not visual.
*/
- @Nullable
+ @NonNull
@Override
public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
- if (mWindow != null) {
- View decorView = mWindow.getDecorView();
- if (decorView != null) {
- return decorView.getOnBackInvokedDispatcher();
- }
+ if (mWindow == null) {
+ throw new IllegalStateException("OnBackInvokedDispatcher are not available on "
+ + "non-visual activities");
}
- return null;
+ return ((OnBackInvokedDispatcherOwner) mWindow).getOnBackInvokedDispatcher();
}
}
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index cce7dd338b3d..a58ceaa99022 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -215,6 +215,14 @@ public abstract class ActivityManagerInternal {
public abstract boolean isSystemReady();
/**
+ * Returns package name given pid.
+ *
+ * @param pid The pid we are searching package name for.
+ */
+ @Nullable
+ public abstract String getPackageNameByPid(int pid);
+
+ /**
* Sets if the given pid has an overlay UI or not.
*
* @param pid The pid we are setting overlay UI for.
diff --git a/core/java/android/app/ApplicationExitInfo.java b/core/java/android/app/ApplicationExitInfo.java
index 9039bbdf62cf..60e22f4ecd12 100644
--- a/core/java/android/app/ApplicationExitInfo.java
+++ b/core/java/android/app/ApplicationExitInfo.java
@@ -156,6 +156,12 @@ public final class ApplicationExitInfo implements Parcelable {
public static final int REASON_OTHER = 13;
/**
+ * Application process was killed by App Freezer, for example, because it receives
+ * sync binder transactions while being frozen.
+ */
+ public static final int REASON_FREEZER = 14;
+
+ /**
* Application process kills subreason is unknown.
*
* For internal use only.
@@ -487,6 +493,7 @@ public final class ApplicationExitInfo implements Parcelable {
REASON_USER_STOPPED,
REASON_DEPENDENCY_DIED,
REASON_OTHER,
+ REASON_FREEZER,
})
@Retention(RetentionPolicy.SOURCE)
public @interface Reason {}
@@ -1138,6 +1145,8 @@ public final class ApplicationExitInfo implements Parcelable {
return "DEPENDENCY DIED";
case REASON_OTHER:
return "OTHER KILLS BY SYSTEM";
+ case REASON_FREEZER:
+ return "FREEZER";
default:
return "UNKNOWN";
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index a7fb83bfcf5e..4b42ddc383b2 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -1449,15 +1449,9 @@ public class Dialog implements DialogInterface, Window.Callback,
*
* Returns null if the dialog is not attached to a window with a decor.
*/
- @Nullable
+ @NonNull
@Override
public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
- if (mWindow != null) {
- View decorView = mWindow.getDecorView();
- if (decorView != null) {
- return decorView.getOnBackInvokedDispatcher();
- }
- }
- return null;
+ return ((OnBackInvokedDispatcherOwner) mWindow).getOnBackInvokedDispatcher();
}
}
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index e4ef12c250ab..7c48a5738e51 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -679,6 +679,10 @@ interface IActivityManager {
*/
boolean isAppFreezerSupported();
+ /**
+ * Return whether the app freezer is enabled (true) or not (false) by this system.
+ */
+ boolean isAppFreezerEnabled();
/**
* Kills uid with the reason of permission change.
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 0801b2481f0c..c5add66e0a14 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -130,6 +130,9 @@ interface IActivityTaskManager {
in ProfilerInfo profilerInfo, in Bundle options, int userId);
int startAssistantActivity(in String callingPackage, in String callingFeatureId, int callingPid,
int callingUid, in Intent intent, in String resolvedType, in Bundle options, int userId);
+ int startActivityFromGameSession(IApplicationThread caller, in String callingPackage,
+ in String callingFeatureId, int callingPid, int callingUid, in Intent intent,
+ int taskId, int userId);
void startRecentsActivity(in Intent intent, in long eventTime,
in IRecentsAnimationRunner recentsAnimationRunner);
int startActivityFromRecents(int taskId, in Bundle options);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 79180cbc57fd..4187ba0a10a5 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -139,12 +139,10 @@ import android.net.ConnectivityFrameworkInitializer;
import android.net.ConnectivityFrameworkInitializerTiramisu;
import android.net.EthernetManager;
import android.net.IEthernetManager;
-import android.net.IIpSecService;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.IPacProxyManager;
import android.net.IVpnManager;
-import android.net.IpSecManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkScoreManager;
import android.net.NetworkWatchlistManager;
@@ -441,15 +439,6 @@ public final class SystemServiceRegistry {
return new VcnManager(ctx, service);
}});
- registerService(Context.IPSEC_SERVICE, IpSecManager.class,
- new CachedServiceFetcher<IpSecManager>() {
- @Override
- public IpSecManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getService(Context.IPSEC_SERVICE);
- IIpSecService service = IIpSecService.Stub.asInterface(b);
- return new IpSecManager(ctx, service);
- }});
-
registerService(Context.COUNTRY_DETECTOR, CountryDetector.class,
new StaticServiceFetcher<CountryDetector>() {
@Override
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 00903a880834..b41b5f005f1f 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -780,6 +780,33 @@ public final class UiAutomation {
}
/**
+ * Sets the system settings values that control the scaling factor for animations. The scale
+ * controls the animation playback speed for animations that respect these settings. Animations
+ * that do not respect the settings values will not be affected by this function. A lower scale
+ * value results in a faster speed. A value of <code>0</code> disables animations entirely. When
+ * animations are disabled services receive window change events more quickly which can reduce
+ * the potential by confusion by reducing the time during which windows are in transition.
+ *
+ * @see AccessibilityEvent#TYPE_WINDOWS_CHANGED
+ * @see AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
+ * @see android.provider.Settings.Global#WINDOW_ANIMATION_SCALE
+ * @see android.provider.Settings.Global#TRANSITION_ANIMATION_SCALE
+ * @see android.provider.Settings.Global#ANIMATOR_DURATION_SCALE
+ * @param scale The scaling factor for all animations.
+ */
+ public void setAnimationScale(float scale) {
+ final IAccessibilityServiceConnection connection =
+ AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+ if (connection != null) {
+ try {
+ connection.setAnimationScale(scale);
+ } catch (RemoteException re) {
+ throw new RuntimeException(re);
+ }
+ }
+ }
+
+ /**
* A request for WindowManagerService to wait until all animations have completed and input
* information has been sent from WindowManager to native InputManager.
*
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 487ce4848419..4704a24d2ca5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1332,7 +1332,10 @@ public class DevicePolicyManager {
*
* <p>Use in an intent with action {@link #ACTION_PROVISION_MANAGED_PROFILE} or
* {@link #ACTION_PROVISION_MANAGED_DEVICE}
+ *
+ * @deprecated Logo customization is no longer supported in the provisioning flow.
*/
+ @Deprecated
public static final String EXTRA_PROVISIONING_LOGO_URI =
"android.app.extra.PROVISIONING_LOGO_URI";
@@ -10135,7 +10138,9 @@ public class DevicePolicyManager {
/**
* Called by a profile owner of secondary user that is affiliated with the device to stop the
- * calling user and switch back to primary user.
+ * calling user and switch back to primary user (when the user was
+ * {@link #switchUser(ComponentName, UserHandle)} switched to) or stop the user (when it was
+ * {@link #startUserInBackground(ComponentName, UserHandle) started in background}.
*
* <p>Notice that on devices running with
* {@link UserManager#isHeadlessSystemUserMode() headless system user mode}, there is no primary
@@ -10163,7 +10168,12 @@ public class DevicePolicyManager {
}
/**
- * Same as {@link #logoutUser(ComponentName)}, but called by system (like Settings), not admin.
+ * Similar to {@link #logoutUser(ComponentName)}, except:
+ *
+ * <ul>
+ * <li>Called by system (like Settings), not admin.
+ * <li>It logs out the current user, not the caller.
+ * </ul>
*
* @hide
*/
@@ -10180,7 +10190,10 @@ public class DevicePolicyManager {
}
/**
* Gets the user a {@link #logoutUser(ComponentName)} call would switch to,
- * or {@code null} if the current user is not in a session.
+ * or {@code null} if the current user is not in a session (i.e., if it was not
+ * {@link #switchUser(ComponentName, UserHandle) switched} or
+ * {@link #startUserInBackground(ComponentName, UserHandle) started in background} by the
+ * device admin.
*
* @hide
*/
@@ -15370,4 +15383,45 @@ public class DevicePolicyManager {
}
return ParcelableResource.loadDefaultString(defaultStringLoader);
}
+
+ /**
+ * Returns a boolean for whether the DPC has been downloaded during provisioning.
+ *
+ * <p>If true is returned, then any attempts to begin setup again should result in factory reset
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public boolean isDpcDownloaded() {
+ throwIfParentInstance("isDpcDownloaded");
+ if (mService != null) {
+ try {
+ return mService.isDpcDownloaded();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Use to indicate that the DPC has or has not been downloaded during provisioning.
+ *
+ * @param downloaded {@code true} if the dpc has been downloaded during provisioning. false otherwise.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS)
+ public void setDpcDownloaded(boolean downloaded) {
+ throwIfParentInstance("setDpcDownloaded");
+ if (mService != null) {
+ try {
+ mService.setDpcDownloaded(downloaded);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
}
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
index ac39cb4f1e23..7f2e5fde70f1 100644
--- a/core/java/android/app/admin/DevicePolicyResources.java
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -58,6 +58,10 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_
import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_GENERIC_MESSAGE;
import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_ORG_OWNED_MESSAGE;
import static android.app.admin.DevicePolicyResources.Strings.Core.WORK_PROFILE_DELETED_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_INCOMING_WORK_CALL_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_MISSED_WORK_CALL_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_ONGOING_WORK_CALL_TITLE;
+import static android.app.admin.DevicePolicyResources.Strings.Dialer.NOTIFICATION_WIFI_WORK_CALL_LABEL;
import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_PERSONAL_MESSAGE;
import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_PERSONAL_TITLE;
import static android.app.admin.DevicePolicyResources.Strings.DocumentsUi.CANT_SAVE_TO_WORK_MESSAGE;
@@ -512,7 +516,11 @@ public final class DevicePolicyResources {
WORK_PROFILE_DEFAULT_APPS_TITLE, HOME_MISSING_WORK_PROFILE_SUPPORT_MESSAGE,
BACKGROUND_ACCESS_DISABLED_BY_ADMIN_MESSAGE, BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
BACKGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE, FOREGROUND_ACCESS_ENABLED_BY_ADMIN_MESSAGE,
- LOCATION_AUTO_GRANTED_MESSAGE
+ LOCATION_AUTO_GRANTED_MESSAGE,
+
+ // Dialer Strings
+ NOTIFICATION_INCOMING_WORK_CALL_TITLE, NOTIFICATION_ONGOING_WORK_CALL_TITLE,
+ NOTIFICATION_MISSED_WORK_CALL_TITLE, NOTIFICATION_WIFI_WORK_CALL_LABEL,
})
public @interface UpdatableStringId {
}
@@ -709,6 +717,7 @@ public final class DevicePolicyResources {
strings.addAll(DocumentsUi.buildStringsSet());
strings.addAll(MediaProvider.buildStringsSet());
strings.addAll(PermissionController.buildStringsSet());
+ strings.addAll(Dialer.buildStringsSet());
return strings;
}
@@ -2934,5 +2943,54 @@ public final class DevicePolicyResources {
return strings;
}
}
+
+ /**
+ * Class containing the identifiers used to update device management-related system strings
+ * in the Dialer app.
+ */
+ public static final class Dialer {
+
+ private Dialer() {
+ }
+
+ private static final String PREFIX = "Dialer.";
+
+ /**
+ * The title of the in-call notification for an incoming work call.
+ */
+ public static final String NOTIFICATION_INCOMING_WORK_CALL_TITLE =
+ PREFIX + "NOTIFICATION_INCOMING_WORK_CALL_TITLE";
+
+ /**
+ * The title of the in-call notification for an ongoing work call.
+ */
+ public static final String NOTIFICATION_ONGOING_WORK_CALL_TITLE =
+ PREFIX + "NOTIFICATION_ONGOING_WORK_CALL_TITLE";
+
+ /**
+ * Missed call notification label, used when there's exactly one missed call from work
+ * contact.
+ */
+ public static final String NOTIFICATION_MISSED_WORK_CALL_TITLE =
+ PREFIX + "NOTIFICATION_MISSED_WORK_CALL_TITLE";
+
+ /**
+ * Label for notification indicating that call is being made over wifi.
+ */
+ public static final String NOTIFICATION_WIFI_WORK_CALL_LABEL =
+ PREFIX + "NOTIFICATION_WIFI_WORK_CALL_LABEL";
+
+ /**
+ * @hide
+ */
+ static Set<String> buildStringsSet() {
+ Set<String> strings = new HashSet<>();
+ strings.add(NOTIFICATION_INCOMING_WORK_CALL_TITLE);
+ strings.add(NOTIFICATION_ONGOING_WORK_CALL_TITLE);
+ strings.add(NOTIFICATION_MISSED_WORK_CALL_TITLE);
+ strings.add(NOTIFICATION_WIFI_WORK_CALL_LABEL);
+ return strings;
+ }
+ }
}
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a7a51f8f6caa..0e1caca2670a 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -555,6 +555,9 @@ interface IDevicePolicyManager {
void resetDrawables(in String[] drawableIds);
ParcelableResource getDrawable(String drawableId, String drawableStyle, String drawableSource);
+ boolean isDpcDownloaded();
+ void setDpcDownloaded(boolean downloaded);
+
void setStrings(in List<DevicePolicyStringResource> strings);
void resetStrings(in String[] stringIds);
ParcelableResource getString(String stringId);
diff --git a/core/java/android/companion/TEST_MAPPING b/core/java/android/companion/TEST_MAPPING
index 63f54fa35158..b561c29c37c4 100644
--- a/core/java/android/companion/TEST_MAPPING
+++ b/core/java/android/companion/TEST_MAPPING
@@ -1,12 +1,7 @@
{
- "presubmit": [
+ "imports": [
{
- "name": "CtsOsTestCases",
- "options": [
- {
- "include-filter": "android.os.cts.CompanionDeviceManagerTest"
- }
- ]
+ "path": "frameworks/base/services/companion"
}
]
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 52681630dab0..207412511198 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -408,6 +408,7 @@ public abstract class Context {
* @hide
*/
@SystemApi
+ @Deprecated
public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 0x00040000;
/**
@@ -421,12 +422,13 @@ public abstract class Context {
public static final int BIND_SCHEDULE_LIKE_TOP_APP = 0x00080000;
/**
- * This flag has never been used.
+ * Flag for {@link #bindService}: allow background activity starts from the bound service's
+ * process.
+ * This flag is only respected if the caller is holding
+ * {@link android.Manifest.permission#START_ACTIVITIES_FROM_BACKGROUND}.
* @hide
- * @deprecated This flag has never been used.
*/
@SystemApi
- @Deprecated
public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 0x00100000;
/**
@@ -3888,7 +3890,6 @@ public abstract class Context {
//@hide: SPEECH_RECOGNITION_SERVICE,
UWB_SERVICE,
MEDIA_METRICS_SERVICE,
- SUPPLEMENTAL_PROCESS_SERVICE,
//@hide: ATTESTATION_VERIFICATION_SERVICE,
//@hide: SAFETY_CENTER_SERVICE,
})
@@ -5970,13 +5971,6 @@ public abstract class Context {
public static final String LOCALE_SERVICE = "locale";
/**
- * Use with {@link #getSystemService(String)} to retrieve a Supplemental Process Manager.
- *
- * @see #getSystemService(String)
- */
- public static final String SUPPLEMENTAL_PROCESS_SERVICE = "supplemental_process";
-
- /**
* Use with {@link #getSystemService(String)} to retrieve a {@link
* android.safetycenter.SafetyCenterManager} instance for interacting with the safety center.
*
@@ -6510,15 +6504,26 @@ public abstract class Context {
* <li>Each permission in {@code permissions} must be a runtime permission.
* </ul>
* <p>
- * For every permission in {@code permissions}, the entire permission group it belongs to will
- * be revoked. The revocation happens asynchronously and kills all processes running in the
- * calling UID. It will be triggered once it is safe to do so. In particular, it will not be
- * triggered as long as the package remains in the foreground, or has any active manifest
- * components (e.g. when another app is accessing a content provider in the package).
+ * Background permissions which have no corresponding foreground permission still granted once
+ * the revocation is effective will also be revoked.
+ * <p>
+ * The revocation happens asynchronously and kills all processes running in the calling UID. It
+ * will be triggered once it is safe to do so. In particular, it will not be triggered as long
+ * as the package remains in the foreground, or has any active manifest components (e.g. when
+ * another app is accessing a content provider in the package).
* <p>
* If you want to revoke the permissions right away, you could call {@code System.exit()}, but
* this could affect other apps that are accessing your app at the moment. For example, apps
* accessing a content provider in your app will all crash.
+ * <p>
+ * Note that the settings UI shows a permission group as granted as long as at least one
+ * permission in the group is granted. If you want the user to observe the revocation in the
+ * settings, you should revoke every permission in the target group. To learn the current list
+ * of permissions in a group, you may use
+ * {@link PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)} and
+ * {@link PackageManager#getPlatformPermissionsForGroup(String, Executor, Consumer)}. This list
+ * of permissions may evolve over time, so it is recommended to check whether it contains any
+ * permission you wish to retain before trying to revoke an entire group.
*
* @param permissions Collection of permissions to be revoked.
* @see PackageManager#getGroupOfPlatformPermission(String, Executor, Consumer)
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3e527f8d5215..28bef566b59c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -5576,6 +5576,7 @@ public class Intent implements Parcelable, Cloneable {
/**
* A String[] holding attribution tags when used with
* {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+ * and ACTION_MANAGE_PERMISSION_USAGE
*
* E.g. an attribution tag could be location_provider, com.google.android.gms.*, etc.
*/
@@ -5584,17 +5585,20 @@ public class Intent implements Parcelable, Cloneable {
/**
* A long representing the start timestamp (epoch time in millis) of the permission usage
* when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+ * and ACTION_MANAGE_PERMISSION_USAGE
*/
public static final String EXTRA_START_TIME = "android.intent.extra.START_TIME";
/**
* A long representing the end timestamp (epoch time in millis) of the permission usage when
* used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+ * and ACTION_MANAGE_PERMISSION_USAGE
*/
public static final String EXTRA_END_TIME = "android.intent.extra.END_TIME";
/**
- * A boolean extra, when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD},
+ * A boolean extra, when used with {@link #ACTION_VIEW_PERMISSION_USAGE_FOR_PERIOD}
+ * and {@link #ACTION_MANAGE_PERMISSION_USAGE},
* that specifies whether the permission usage system UI is showing attribution information
* for the chosen entry.
*
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9e9dd1edd577..567f649ea762 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -19,6 +19,7 @@ package android.content.pm;
import static android.os.Build.VERSION_CODES.DONUT;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -48,6 +49,7 @@ import java.lang.annotation.RetentionPolicy;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
@@ -62,58 +64,58 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
private static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
/**
- * Default task affinity of all activities in this application. See
- * {@link ActivityInfo#taskAffinity} for more information. This comes
- * from the "taskAffinity" attribute.
+ * Default task affinity of all activities in this application. See
+ * {@link ActivityInfo#taskAffinity} for more information. This comes
+ * from the "taskAffinity" attribute.
*/
public String taskAffinity;
-
+
/**
* Optional name of a permission required to be able to access this
* application's components. From the "permission" attribute.
*/
public String permission;
-
+
/**
* The name of the process this application should run in. From the
* "process" attribute or, if not set, the same as
* <var>packageName</var>.
*/
public String processName;
-
+
/**
* Class implementing the Application object. From the "class"
* attribute.
*/
public String className;
-
+
/**
* A style resource identifier (in the package's resources) of the
* description of an application. From the "description" attribute
* or, if not set, 0.
*/
- public int descriptionRes;
-
+ public int descriptionRes;
+
/**
* A style resource identifier (in the package's resources) of the
* default visual theme of the application. From the "theme" attribute
* or, if not set, 0.
*/
public int theme;
-
+
/**
* Class implementing the Application's manage space
* functionality. From the "manageSpaceActivity"
* attribute. This is an optional attribute and will be null if
* applications don't specify it in their manifest
*/
- public String manageSpaceActivityName;
-
+ public String manageSpaceActivityName;
+
/**
* Class implementing the Application's backup functionality. From
* the "backupAgent" attribute. This is an optional attribute and
* will be null if the application does not specify it in its manifest.
- *
+ *
* <p>If android:allowBackup is set to false, this attribute is ignored.
*/
public String backupAgentName;
@@ -174,7 +176,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* {@code signatureOrSystem}.
*/
public static final int FLAG_SYSTEM = 1<<0;
-
+
/**
* Value for {@link #flags}: set to true if this application would like to
* allow debugging of its
@@ -183,7 +185,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* android:debuggable} of the &lt;application&gt; tag.
*/
public static final int FLAG_DEBUGGABLE = 1<<1;
-
+
/**
* Value for {@link #flags}: set to true if this application has code
* associated with it. Comes
@@ -191,7 +193,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* android:hasCode} of the &lt;application&gt; tag.
*/
public static final int FLAG_HAS_CODE = 1<<2;
-
+
/**
* Value for {@link #flags}: set to true if this application is persistent.
* Comes from {@link android.R.styleable#AndroidManifestApplication_persistent
@@ -212,20 +214,20 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* android:allowTaskReparenting} of the &lt;application&gt; tag.
*/
public static final int FLAG_ALLOW_TASK_REPARENTING = 1<<5;
-
+
/**
* Value for {@link #flags}: default value for the corresponding ActivityInfo flag.
* Comes from {@link android.R.styleable#AndroidManifestApplication_allowClearUserData
* android:allowClearUserData} of the &lt;application&gt; tag.
*/
public static final int FLAG_ALLOW_CLEAR_USER_DATA = 1<<6;
-
+
/**
* Value for {@link #flags}: this is set if this application has been
* installed as an update to a built-in system application.
*/
public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7;
-
+
/**
* Value for {@link #flags}: this is set if the application has specified
* {@link android.R.styleable#AndroidManifestApplication_testOnly
@@ -240,15 +242,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* android:smallScreens}.
*/
public static final int FLAG_SUPPORTS_SMALL_SCREENS = 1<<9;
-
+
/**
* Value for {@link #flags}: true when the application's window can be
* displayed on normal screens. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_normalScreens
* android:normalScreens}.
*/
- public static final int FLAG_SUPPORTS_NORMAL_SCREENS = 1<<10;
-
+ public static final int FLAG_SUPPORTS_NORMAL_SCREENS = 1<<10;
+
/**
* Value for {@link #flags}: true when the application's window can be
* increased in size for larger screens. Corresponds to
@@ -256,7 +258,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* android:largeScreens}.
*/
public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<11;
-
+
/**
* Value for {@link #flags}: true when the application knows how to adjust
* its UI for different screen sizes. Corresponds to
@@ -264,7 +266,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* android:resizeable}.
*/
public static final int FLAG_RESIZEABLE_FOR_SCREENS = 1<<12;
-
+
/**
* Value for {@link #flags}: true when the application knows how to
* accommodate different screen densities. Corresponds to
@@ -276,7 +278,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
@Deprecated
public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 1<<13;
-
+
/**
* Value for {@link #flags}: set to true if this application would like to
* request the VM to operate under the safe mode. Comes from
@@ -288,7 +290,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/**
* Value for {@link #flags}: set to <code>false</code> if the application does not wish
* to permit any OS-driven backups of its data; <code>true</code> otherwise.
- *
+ *
* <p>Comes from the
* {@link android.R.styleable#AndroidManifestApplication_allowBackup android:allowBackup}
* attribute of the &lt;application&gt; tag.
@@ -351,7 +353,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* android:xlargeScreens}.
*/
public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19;
-
+
/**
* Value for {@link #flags}: true when the application has requested a
* large heap for its processes. Corresponds to
@@ -1114,7 +1116,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
* the same uid).
*/
public int uid;
-
+
/**
* The minimum SDK version this application can run on. It will not run
* on earlier versions.
@@ -1817,7 +1819,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
if (sb == null) {
sb = ab.packageName;
}
-
+
return sCollator.compare(sa.toString(), sb.toString());
}
@@ -1830,7 +1832,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public ApplicationInfo() {
createTimestamp = System.currentTimeMillis();
}
-
+
public ApplicationInfo(ApplicationInfo orig) {
super(orig);
taskAffinity = orig.taskAffinity;
@@ -2125,7 +2127,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/**
* Disable compatibility mode
- *
+ *
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -2346,7 +2348,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
return pm.getDefaultActivityIcon();
}
-
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean isPackageUnavailable(PackageManager pm) {
try {
@@ -2655,4 +2657,22 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public int getLocaleConfigRes() {
return localeConfigRes;
}
+
+
+ /**
+ * List of all shared libraries this application is linked against. This
+ * list will only be set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
+ * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving the structure.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public List<SharedLibraryInfo> getSharedLibraryInfos() {
+ if (sharedLibraryInfos == null) {
+ return Collections.EMPTY_LIST;
+ }
+ return sharedLibraryInfos;
+ }
+
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index aa647000ee2d..07227c5fe0e1 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1063,6 +1063,7 @@ public abstract class PackageManager {
* via this flag.
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int MATCH_STATIC_SHARED_AND_SDK_LIBRARIES = 0x04000000;
/**
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index c12e8195eeb4..d6d3a97687b5 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -25,6 +25,7 @@ import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.graphics.Point;
import android.hardware.CameraStatus;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceListener;
@@ -458,12 +459,14 @@ public final class CameraManager {
(DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
if (display != null) {
- int width = display.getWidth();
- int height = display.getHeight();
+ Point sz = new Point();
+ display.getRealSize(sz);
+ int width = sz.x;
+ int height = sz.y;
if (height > width) {
height = width;
- width = display.getHeight();
+ width = sz.y;
}
ret = new Size(width, height);
@@ -471,7 +474,7 @@ public final class CameraManager {
Log.e(TAG, "Invalid default display!");
}
} catch (Exception e) {
- Log.e(TAG, "getDisplaySize Failed. " + e.toString());
+ Log.e(TAG, "getDisplaySize Failed. " + e);
}
return ret;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index fc2fbc39dbeb..223b8ccf44c8 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -346,7 +346,7 @@ public class InputMethodService extends AbstractInputMethodService {
*/
@AnyThread
public static boolean canImeRenderGesturalNavButtons() {
- return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, true);
+ return SystemProperties.getBoolean(PROP_CAN_RENDER_GESTURAL_NAV_BUTTONS, false);
}
/**
diff --git a/core/java/android/inputmethodservice/NavigationBarController.java b/core/java/android/inputmethodservice/NavigationBarController.java
index e5c22e4de08e..83fc7276eabc 100644
--- a/core/java/android/inputmethodservice/NavigationBarController.java
+++ b/core/java/android/inputmethodservice/NavigationBarController.java
@@ -546,7 +546,8 @@ final class NavigationBarController {
public String toDebugString() {
return "{mRenderGesturalNavButtons=" + mRenderGesturalNavButtons
+ " mNavigationBarFrame=" + mNavigationBarFrame
- + " mShouldShowImeSwitcherWhenImeIsShown" + mShouldShowImeSwitcherWhenImeIsShown
+ + " mShouldShowImeSwitcherWhenImeIsShown="
+ + mShouldShowImeSwitcherWhenImeIsShown
+ " mAppearance=0x" + Integer.toHexString(mAppearance)
+ " mDarkIntensity=" + mDarkIntensity
+ " mDrawLegacyNavigationBarBackground=" + mDrawLegacyNavigationBarBackground
diff --git a/core/java/android/os/BatteryStatsManager.java b/core/java/android/os/BatteryStatsManager.java
index f16bbc66e6cd..071bdea5e3ac 100644
--- a/core/java/android/os/BatteryStatsManager.java
+++ b/core/java/android/os/BatteryStatsManager.java
@@ -24,8 +24,6 @@ import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
import android.content.Context;
import android.net.NetworkStack;
import android.os.connectivity.CellularBatteryStats;
@@ -523,8 +521,6 @@ public final class BatteryStatsManager {
* @param reason why Bluetooth has been turned on
* @param packageName package responsible for this change
*/
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void reportBluetoothOn(int uid, int reason, @NonNull String packageName) {
try {
@@ -541,8 +537,6 @@ public final class BatteryStatsManager {
* @param reason why Bluetooth has been turned on
* @param packageName package responsible for this change
*/
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
@RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
public void reportBluetoothOff(int uid, int reason, @NonNull String packageName) {
try {
diff --git a/core/java/android/os/logcat/ILogcatManagerService.aidl b/core/java/android/os/logcat/ILogcatManagerService.aidl
index 68b5679919d6..02db2749bbe8 100644
--- a/core/java/android/os/logcat/ILogcatManagerService.aidl
+++ b/core/java/android/os/logcat/ILogcatManagerService.aidl
@@ -22,5 +22,7 @@ package android.os.logcat;
interface ILogcatManagerService {
void startThread(in int uid, in int gid, in int pid, in int fd);
void finishThread(in int uid, in int gid, in int pid, in int fd);
+ void approve(in int uid, in int gid, in int pid, in int fd);
+ void decline(in int uid, in int gid, in int pid, in int fd);
}
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 1c0320e9a86e..619c8705ddae 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -79,7 +79,8 @@ interface IPermissionManager {
void revokeOwnPermissionsOnKill(String packageName, in List<String> permissions);
void startOneTimePermissionSession(String packageName, int userId, long timeout,
- int importanceToResetTimer, int importanceToKeepSessionAlive);
+ long revokeAfterKilledDelay, int importanceToResetTimer,
+ int importanceToKeepSessionAlive);
void stopOneTimePermissionSession(String packageName, int userId);
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 0cf06aa364ec..a005ab4e6ac7 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -907,21 +907,23 @@ public final class PermissionControllerManager {
* <li>Each permission in {@code permissions} must be a runtime permission.
* </ul>
* <p>
- * For every permission in {@code permissions}, the entire permission group it belongs to will
- * be revoked. This revocation happens asynchronously and kills all processes running in the
- * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+ * Background permissions which have no corresponding foreground permission still granted once
+ * the revocation is effective will also be revoked.
+ * <p>
+ * This revocation happens asynchronously and kills all processes running in the same UID as
+ * {@code packageName}. It will be triggered once it is safe to do so.
*
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
- * @param callback Callback called when the revocation request has been completed.
*
- * @see Context#revokeOwnPermissionsOnKill(Collection)
+ * @see Context#revokeOwnPermissionsOnKill(java.util.Collection)
*
* @hide
*/
public void revokeOwnPermissionsOnKill(@NonNull String packageName,
- @NonNull List<String> permissions, AndroidFuture<Void> callback) {
+ @NonNull List<String> permissions) {
mRemoteService.postAsync(service -> {
+ AndroidFuture<Void> callback = new AndroidFuture<>();
service.revokeOwnPermissionsOnKill(packageName, permissions, callback);
return callback;
}).whenComplete((result, err) -> {
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 8d9f82b04b54..3292e7110ee5 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -291,7 +291,7 @@ public abstract class PermissionControllerService extends Service {
/**
* Called when a package is considered inactive based on the criteria given by
- * {@link PermissionManager#startOneTimePermissionSession(String, long, int, int)}.
+ * {@link PermissionManager#startOneTimePermissionSession(String, long, long, int, int)}.
* This method is called at the end of a one-time permission session
*
* @param packageName The package that has been inactive
@@ -329,9 +329,11 @@ public abstract class PermissionControllerService extends Service {
* Triggers the revocation of one or more permissions for a package. This should only be called
* at the request of {@code packageName}.
* <p>
- * For every permission in {@code permissions}, the entire permission group it belongs to will
- * be revoked. This revocation happens asynchronously and kills all processes running in the
- * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+ * Background permissions which have no corresponding foreground permission still granted once
+ * the revocation is effective will also be revoked.
+ * <p>
+ * This revocation happens asynchronously and kills all processes running in the same UID as
+ * {@code packageName}. It will be triggered once it is safe to do so.
*
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 15f13eb89cb9..12fa0ddfc648 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -20,6 +20,7 @@ import static android.os.Build.VERSION_CODES.S;
import android.Manifest;
import android.annotation.CheckResult;
+import android.annotation.DurationMillisLong;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1282,6 +1283,22 @@ public final class PermissionManager {
}
/**
+ * Starts a one-time permission session for a given package.
+ * @see #startOneTimePermissionSession(String, long, long, int, int)
+ * @hide
+ * @deprecated Use {@link #startOneTimePermissionSession(String, long, long, int, int)} instead
+ */
+ @Deprecated
+ @SystemApi
+ @RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
+ public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
+ @ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
+ @ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
+ startOneTimePermissionSession(packageName, timeoutMillis, -1,
+ importanceToResetTimer, importanceToKeepSessionAlive);
+ }
+
+ /**
* Starts a one-time permission session for a given package. A one-time permission session is
* ended if app becomes inactive. Inactivity is defined as the package's uid importance level
* staying > importanceToResetTimer for timeoutMillis milliseconds. If the package's uid
@@ -1301,25 +1318,33 @@ public final class PermissionManager {
* {@link PermissionControllerService#onOneTimePermissionSessionTimeout(String)} is invoked.
* </p>
* <p>
- * Note that if there is currently an active session for a package a new one isn't created and
- * the existing one isn't changed.
+ * Note that if there is currently an active session for a package a new one isn't created but
+ * each parameter of the existing one will be updated to the more aggressive of both sessions.
+ * This means that durations will be set to the shortest parameter and importances will be set
+ * to the lowest one.
* </p>
* @param packageName The package to start a one-time permission session for
* @param timeoutMillis Number of milliseconds for an app to be in an inactive state
+ * @param revokeAfterKilledDelayMillis Number of milliseconds to wait before revoking on the
+ * event an app is terminated. Set to -1 to use default
+ * value for the device.
* @param importanceToResetTimer The least important level to uid must be to reset the timer
* @param importanceToKeepSessionAlive The least important level the uid must be to keep the
- * session alive
+ * session alive
*
* @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS)
- public void startOneTimePermissionSession(@NonNull String packageName, long timeoutMillis,
+ public void startOneTimePermissionSession(@NonNull String packageName,
+ @DurationMillisLong long timeoutMillis,
+ @DurationMillisLong long revokeAfterKilledDelayMillis,
@ActivityManager.RunningAppProcessInfo.Importance int importanceToResetTimer,
@ActivityManager.RunningAppProcessInfo.Importance int importanceToKeepSessionAlive) {
try {
mPermissionManager.startOneTimePermissionSession(packageName, mContext.getUserId(),
- timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
+ timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer,
+ importanceToKeepSessionAlive);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/service/games/GameSession.java b/core/java/android/service/games/GameSession.java
index e33f1801129b..468e087c941b 100644
--- a/core/java/android/service/games/GameSession.java
+++ b/core/java/android/service/games/GameSession.java
@@ -20,15 +20,23 @@ import android.annotation.Hide;
import android.annotation.IntDef;
import android.annotation.MainThread;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
+import android.app.ActivityTaskManager;
+import android.app.Instrumentation;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Slog;
import android.view.SurfaceControlViewHost;
import android.view.View;
@@ -41,6 +49,7 @@ import com.android.internal.util.function.pooled.PooledLambda;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
import java.util.concurrent.Executor;
/**
@@ -120,6 +129,7 @@ public abstract class GameSession {
private LifecycleState mLifecycleState = LifecycleState.INITIALIZED;
private boolean mAreTransientInsetsVisibleDueToGesture = false;
private IGameSessionController mGameSessionController;
+ private Context mContext;
private int mTaskId;
private GameSessionRootView mGameSessionRootView;
private SurfaceControlViewHost mSurfaceControlViewHost;
@@ -137,6 +147,7 @@ public abstract class GameSession {
int heightPx) {
mGameSessionController = gameSessionController;
mTaskId = taskId;
+ mContext = context;
mSurfaceControlViewHost = surfaceControlViewHost;
mGameSessionRootView = new GameSessionRootView(context, mSurfaceControlViewHost);
surfaceControlViewHost.setView(mGameSessionRootView, widthPx, heightPx);
@@ -299,6 +310,8 @@ public abstract class GameSession {
* {@code View} may not be cleared once set, but may be replaced by invoking
* {@link #setTaskOverlayView(View, ViewGroup.LayoutParams)} again.
*
+ * <p><b>WARNING</b>: Callers <b>must</b> ensure that only trusted views are provided.
+ *
* @param view The desired content to display.
* @param layoutParams Layout parameters for the view.
*/
@@ -456,4 +469,67 @@ public abstract class GameSession {
break;
}
}
+
+ /**
+ * Launches an activity within the same activity stack as the {@link GameSession}. When the
+ * target activity exits, {@link GameSessionActivityCallback#onActivityResult(int, Intent)} will
+ * be invoked with the result code and result data directly from the target activity (in other
+ * words, the result code and data set via the target activity's
+ * {@link android.app.Activity#startActivityForResult} call). The caller is expected to handle
+ * the results that the target activity returns.
+ *
+ * <p>Any activity that an app would normally be able to start via {@link
+ * android.app.Activity#startActivityForResult} will be startable via this method.
+ *
+ * <p>Started activities may see a different calling package than the game session's package
+ * when calling {@link android.app.Activity#getCallingPackage()}.
+ *
+ * <p> If an exception is thrown while handling {@code intent},
+ * {@link GameSessionActivityCallback#onActivityStartFailed(Throwable)} will be called instead
+ * of {@link GameSessionActivityCallback#onActivityResult(int, Intent)}.
+ *
+ * @param intent The intent to start.
+ * @param options Additional options for how the Activity should be started. See
+ * {@link android.app.Activity#startActivityForResult(Intent, int, Bundle)} for
+ * more details. This value may be null.
+ * @param executor Executor on which {@code callback} should be invoked.
+ * @param callback Callback to be invoked once the started activity has finished.
+ */
+ @RequiresPermission(android.Manifest.permission.MANAGE_GAME_ACTIVITY)
+ public final void startActivityFromGameSessionForResult(
+ @NonNull Intent intent, @Nullable Bundle options, @NonNull Executor executor,
+ @NonNull GameSessionActivityCallback callback) {
+ Objects.requireNonNull(intent);
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(callback);
+
+ AndroidFuture<GameSessionActivityResult> future =
+ new AndroidFuture<GameSessionActivityResult>()
+ .whenCompleteAsync((result, ex) -> {
+ if (ex != null) {
+ callback.onActivityStartFailed(ex);
+ return;
+ }
+ callback.onActivityResult(result.getResultCode(), result.getData());
+ }, executor);
+
+ final Intent trampolineIntent = new Intent();
+ trampolineIntent.setComponent(
+ new ComponentName(
+ "android", "android.service.games.GameSessionTrampolineActivity"));
+ trampolineIntent.putExtra(GameSessionTrampolineActivity.INTENT_KEY, intent);
+ trampolineIntent.putExtra(GameSessionTrampolineActivity.OPTIONS_KEY, options);
+ trampolineIntent.putExtra(
+ GameSessionTrampolineActivity.FUTURE_KEY, future);
+
+ try {
+ int result = ActivityTaskManager.getService().startActivityFromGameSession(
+ mContext.getIApplicationThread(), mContext.getPackageName(), "GameSession",
+ Binder.getCallingPid(), Binder.getCallingUid(), trampolineIntent, mTaskId,
+ UserHandle.myUserId());
+ Instrumentation.checkStartActivityResult(result, trampolineIntent);
+ } catch (Throwable t) {
+ executor.execute(() -> callback.onActivityStartFailed(t));
+ }
+ }
}
diff --git a/core/java/android/service/games/GameSessionActivityCallback.java b/core/java/android/service/games/GameSessionActivityCallback.java
new file mode 100644
index 000000000000..3b11df1fe644
--- /dev/null
+++ b/core/java/android/service/games/GameSessionActivityCallback.java
@@ -0,0 +1,54 @@
+/*
+ * 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.service.games;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Intent;
+import android.os.Bundle;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Callback invoked when an activity launched via
+ * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+ * GameSessionActivityCallback)}} has returned a result or failed to start.
+ *
+ * @hide
+ */
+@SystemApi
+public interface GameSessionActivityCallback {
+ /**
+ * Callback invoked when an activity launched via
+ * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+ * GameSessionActivityCallback)}} has returned a result.
+ *
+ * @param resultCode The result code of the launched activity. See {@link
+ * android.app.Activity#setResult(int)}.
+ * @param data Any data returned by the launched activity. See {@link
+ * android.app.Activity#setResult(int, Intent)}.
+ */
+ void onActivityResult(int resultCode, @Nullable Intent data);
+
+ /**
+ * Callback invoked when a throwable was thrown when launching the {@link Intent} in
+ * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+ * GameSessionActivityCallback)}}.
+ */
+ default void onActivityStartFailed(@NonNull Throwable t) {}
+}
diff --git a/core/java/android/service/games/GameSessionActivityResult.java b/core/java/android/service/games/GameSessionActivityResult.java
new file mode 100644
index 000000000000..a2ec6ada010c
--- /dev/null
+++ b/core/java/android/service/games/GameSessionActivityResult.java
@@ -0,0 +1,71 @@
+/*
+ * 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.service.games;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+final class GameSessionActivityResult implements Parcelable {
+
+ public static final Creator<GameSessionActivityResult> CREATOR =
+ new Creator<GameSessionActivityResult>() {
+ @Override
+ public GameSessionActivityResult createFromParcel(Parcel in) {
+ int resultCode = in.readInt();
+ Intent data = in.readParcelable(Intent.class.getClassLoader(), Intent.class);
+ return new GameSessionActivityResult(resultCode, data);
+ }
+
+ @Override
+ public GameSessionActivityResult[] newArray(int size) {
+ return new GameSessionActivityResult[size];
+ }
+ };
+
+ private final int mResultCode;
+ @Nullable
+ private final Intent mData;
+
+ GameSessionActivityResult(int resultCode, @Nullable Intent data) {
+ mResultCode = resultCode;
+ mData = data;
+ }
+
+ int getResultCode() {
+ return mResultCode;
+ }
+
+ @Nullable
+ Intent getData() {
+ return mData;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mResultCode);
+ dest.writeParcelable(mData, flags);
+ }
+}
diff --git a/core/java/android/service/games/GameSessionTrampolineActivity.java b/core/java/android/service/games/GameSessionTrampolineActivity.java
new file mode 100644
index 000000000000..ddea098680ea
--- /dev/null
+++ b/core/java/android/service/games/GameSessionTrampolineActivity.java
@@ -0,0 +1,79 @@
+/*
+ * 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.service.games;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Slog;
+
+import com.android.internal.infra.AndroidFuture;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Trampoline activity that enables the
+ * {@link GameSession#startActivityFromGameSessionForResult(Intent, Bundle, Executor,
+ * GameSessionActivityCallback)} API by reusing existing activity result infrastructure in the
+ * {@link Activity} class. This activity forwards activity results back to the calling
+ * {@link GameSession} via {@link AndroidFuture}.
+ *
+ * @hide
+ */
+public final class GameSessionTrampolineActivity extends Activity {
+ private static final String TAG = "GameSessionTrampoline";
+ private static final int REQUEST_CODE = 1;
+
+ static final String FUTURE_KEY = "GameSessionTrampolineActivity.future";
+ static final String INTENT_KEY = "GameSessionTrampolineActivity.intent";
+ static final String OPTIONS_KEY = "GameSessionTrampolineActivity.options";
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ try {
+ startActivityAsCaller(
+ getIntent().getParcelableExtra(INTENT_KEY),
+ getIntent().getBundleExtra(OPTIONS_KEY),
+ null,
+ false,
+ getUserId(),
+ REQUEST_CODE);
+ } catch (Exception e) {
+ Slog.w(TAG, "Unable to launch activity from game session");
+ AndroidFuture<GameSessionActivityResult> future = getIntent().getParcelableExtra(
+ FUTURE_KEY);
+ future.completeExceptionally(e);
+ finish();
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode != REQUEST_CODE) {
+ // Something went very wrong if we hit this code path, and we should bail.
+ throw new IllegalStateException("Unexpected request code: " + requestCode);
+ }
+
+ AndroidFuture<GameSessionActivityResult> future = getIntent().getParcelableExtra(
+ FUTURE_KEY);
+ future.complete(new GameSessionActivityResult(resultCode, data));
+ finish();
+ }
+}
diff --git a/core/java/android/view/OnBackInvokedDispatcher.java b/core/java/android/view/OnBackInvokedDispatcher.java
index 05c312b56cc7..f3ca531f2a42 100644
--- a/core/java/android/view/OnBackInvokedDispatcher.java
+++ b/core/java/android/view/OnBackInvokedDispatcher.java
@@ -19,6 +19,7 @@ package android.view;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
+import android.os.Build;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -32,6 +33,13 @@ import java.lang.annotation.RetentionPolicy;
* target (a.k.a. the callback to be invoked next), or its behavior.
*/
public abstract class OnBackInvokedDispatcher {
+
+ /** @hide */
+ public static final String TAG = "OnBackInvokedDispatcher";
+
+ /** @hide */
+ public static final boolean DEBUG = Build.isDebuggable();
+
/** @hide */
@IntDef({
PRIORITY_DEFAULT,
diff --git a/core/java/android/view/OnBackInvokedDispatcherOwner.java b/core/java/android/view/OnBackInvokedDispatcherOwner.java
index 0e14ed4cdb07..e69efe01138c 100644
--- a/core/java/android/view/OnBackInvokedDispatcherOwner.java
+++ b/core/java/android/view/OnBackInvokedDispatcherOwner.java
@@ -16,7 +16,7 @@
package android.view;
-import android.annotation.Nullable;
+import android.annotation.NonNull;
/**
* A class that provides an {@link OnBackInvokedDispatcher} that allows you to register
@@ -28,6 +28,6 @@ public interface OnBackInvokedDispatcherOwner {
* to its registered {@link OnBackInvokedCallback}s.
* Returns null when the root view is not attached to a window or a view tree with a decor.
*/
- @Nullable
+ @NonNull
OnBackInvokedDispatcher getOnBackInvokedDispatcher();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4ff7e2297ea0..22c66dc7aee6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -834,7 +834,7 @@ import java.util.function.Predicate;
*/
@UiThread
public class View implements Drawable.Callback, KeyEvent.Callback,
- AccessibilityEventSource, OnBackInvokedDispatcherOwner {
+ AccessibilityEventSource {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private static final boolean DBG = false;
@@ -12290,7 +12290,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* @return whether this view should have haptic feedback enabled for events
- * long presses.
+ * such as long presses.
*
* @see #setHapticFeedbackEnabled(boolean)
* @see #performHapticFeedback(int)
@@ -31447,23 +31447,4 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
return null;
}
-
- /**
- * Returns the {@link OnBackInvokedDispatcher} instance of the window this view is attached to.
- *
- * @return The {@link OnBackInvokedDispatcher} or {@code null} if the view is neither attached
- * to a window or a view tree with a decor.
- */
- @Nullable
- public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
- ViewParent parent = getParent();
- if (parent instanceof View) {
- return ((View) parent).getOnBackInvokedDispatcher();
- } else if (parent instanceof ViewRootImpl) {
- // Get the fallback dispatcher on {@link ViewRootImpl} if the view tree doesn't have
- // a {@link com.android.internal.policy.DecorView}.
- return ((ViewRootImpl) parent).getOnBackInvokedDispatcher();
- }
- return null;
- }
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 386b277156e3..3d8653554efd 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -236,7 +236,7 @@ import java.util.function.Consumer;
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
- AttachedSurfaceControl {
+ AttachedSurfaceControl, OnBackInvokedDispatcherOwner {
private static final String TAG = "ViewRootImpl";
private static final boolean DBG = false;
private static final boolean LOCAL_LOGV = false;
@@ -313,9 +313,9 @@ public final class ViewRootImpl implements ViewParent,
private @SurfaceControl.BufferTransform
int mPreviousTransformHint = SurfaceControl.BUFFER_TRANSFORM_IDENTITY;
/**
- * The fallback {@link OnBackInvokedDispatcher} when the window doesn't have a decor view.
+ * The top level {@link OnBackInvokedDispatcher}.
*/
- private WindowOnBackInvokedDispatcher mFallbackOnBackInvokedDispatcher =
+ private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher =
new WindowOnBackInvokedDispatcher();
/**
@@ -893,7 +893,6 @@ public final class ViewRootImpl implements ViewParent,
mFastScrollSoundEffectsEnabled = audioManager.areNavigationRepeatSoundEffectsEnabled();
mScrollCaptureRequestTimeout = SCROLL_CAPTURE_REQUEST_TIMEOUT_MILLIS;
- mFallbackOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow);
}
public static void addFirstDrawHandler(Runnable callback) {
@@ -1144,9 +1143,6 @@ public final class ViewRootImpl implements ViewParent,
if (pendingInsetsController != null) {
pendingInsetsController.replayAndAttach(mInsetsController);
}
- ((RootViewSurfaceTaker) mView)
- .provideWindowOnBackInvokedDispatcher()
- .attachToWindow(mWindowSession, mWindow);
}
try {
@@ -1193,6 +1189,7 @@ public final class ViewRootImpl implements ViewParent,
getAttachedWindowFrame(), 1f /* compactScale */,
mTmpFrames.displayFrame, mTempRect2, mTmpFrames.frame);
setFrame(mTmpFrames.frame);
+ registerBackCallbackOnWindow();
if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow);
if (res < WindowManagerGlobal.ADD_OKAY) {
mAttachInfo.mRootView = null;
@@ -8417,6 +8414,7 @@ public final class ViewRootImpl implements ViewParent,
mAdded = false;
}
+ mOnBackInvokedDispatcher.detachFromWindow();
WindowManagerGlobal.getInstance().doRemoveView(this);
}
@@ -10771,12 +10769,17 @@ public final class ViewRootImpl implements ViewParent,
* Returns the {@link OnBackInvokedDispatcher} on the decor view if one exists, or the
* fallback {@link OnBackInvokedDispatcher} instance.
*/
- @Nullable
- public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
- if (mView instanceof RootViewSurfaceTaker) {
- return ((RootViewSurfaceTaker) mView).provideWindowOnBackInvokedDispatcher();
- }
- return mFallbackOnBackInvokedDispatcher;
+ @NonNull
+ public WindowOnBackInvokedDispatcher getOnBackInvokedDispatcher() {
+ return mOnBackInvokedDispatcher;
+ }
+
+ /**
+ * When this ViewRootImpl is added to the window manager, transfers the first
+ * {@link OnBackInvokedCallback} to be called to the server.
+ */
+ private void registerBackCallbackOnWindow() {
+ mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow);
}
@Override
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index 3914a3c963b6..fadbdbbe8746 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -1251,18 +1251,19 @@ public abstract class Animation implements Cloneable {
public float value;
/**
- * Size descriptions can appear inthree forms:
+ * Size descriptions can appear in four forms:
* <ol>
* <li>An absolute size. This is represented by a number.</li>
* <li>A size relative to the size of the object being animated. This
- * is represented by a number followed by "%".</li> *
+ * is represented by a number followed by "%".</li>
* <li>A size relative to the size of the parent of object being
* animated. This is represented by a number followed by "%p".</li>
+ * <li>(Starting from API 32) A complex number.</li>
* </ol>
* @param value The typed value to parse
* @return The parsed version of the description
*/
- static Description parseValue(TypedValue value) {
+ static Description parseValue(TypedValue value, Context context) {
Description d = new Description();
if (value == null) {
d.type = ABSOLUTE;
@@ -1283,6 +1284,11 @@ public abstract class Animation implements Cloneable {
d.type = ABSOLUTE;
d.value = value.data;
return d;
+ } else if (value.type == TypedValue.TYPE_DIMENSION) {
+ d.type = ABSOLUTE;
+ d.value = TypedValue.complexToDimension(value.data,
+ context.getResources().getDisplayMetrics());
+ return d;
}
}
diff --git a/core/java/android/view/animation/ClipRectAnimation.java b/core/java/android/view/animation/ClipRectAnimation.java
index 21509d3a1159..3f4b3e7b4c80 100644
--- a/core/java/android/view/animation/ClipRectAnimation.java
+++ b/core/java/android/view/animation/ClipRectAnimation.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.util.DisplayMetrics;
/**
* An animation that controls the clip of an object. See the
@@ -66,43 +65,43 @@ public class ClipRectAnimation extends Animation {
com.android.internal.R.styleable.ClipRectAnimation);
Description d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ClipRectAnimation_fromLeft));
+ com.android.internal.R.styleable.ClipRectAnimation_fromLeft), context);
mFromLeftType = d.type;
mFromLeftValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ClipRectAnimation_fromTop));
+ com.android.internal.R.styleable.ClipRectAnimation_fromTop), context);
mFromTopType = d.type;
mFromTopValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ClipRectAnimation_fromRight));
+ com.android.internal.R.styleable.ClipRectAnimation_fromRight), context);
mFromRightType = d.type;
mFromRightValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ClipRectAnimation_fromBottom));
+ com.android.internal.R.styleable.ClipRectAnimation_fromBottom), context);
mFromBottomType = d.type;
mFromBottomValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ClipRectAnimation_toLeft));
+ com.android.internal.R.styleable.ClipRectAnimation_toLeft), context);
mToLeftType = d.type;
mToLeftValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ClipRectAnimation_toTop));
+ com.android.internal.R.styleable.ClipRectAnimation_toTop), context);
mToTopType = d.type;
mToTopValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ClipRectAnimation_toRight));
+ com.android.internal.R.styleable.ClipRectAnimation_toRight), context);
mToRightType = d.type;
mToRightValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ClipRectAnimation_toBottom));
+ com.android.internal.R.styleable.ClipRectAnimation_toBottom), context);
mToBottomType = d.type;
mToBottomValue = d.value;
diff --git a/core/java/android/view/animation/ExtendAnimation.java b/core/java/android/view/animation/ExtendAnimation.java
index fd627e50ab0e..210eb8a1ca9d 100644
--- a/core/java/android/view/animation/ExtendAnimation.java
+++ b/core/java/android/view/animation/ExtendAnimation.java
@@ -63,43 +63,43 @@ public class ExtendAnimation extends Animation {
com.android.internal.R.styleable.ExtendAnimation);
Description d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ExtendAnimation_fromExtendLeft));
+ com.android.internal.R.styleable.ExtendAnimation_fromExtendLeft), context);
mFromLeftType = d.type;
mFromLeftValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ExtendAnimation_fromExtendTop));
+ com.android.internal.R.styleable.ExtendAnimation_fromExtendTop), context);
mFromTopType = d.type;
mFromTopValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ExtendAnimation_fromExtendRight));
+ com.android.internal.R.styleable.ExtendAnimation_fromExtendRight), context);
mFromRightType = d.type;
mFromRightValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ExtendAnimation_fromExtendBottom));
+ com.android.internal.R.styleable.ExtendAnimation_fromExtendBottom), context);
mFromBottomType = d.type;
mFromBottomValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ExtendAnimation_toExtendLeft));
+ com.android.internal.R.styleable.ExtendAnimation_toExtendLeft), context);
mToLeftType = d.type;
mToLeftValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ExtendAnimation_toExtendTop));
+ com.android.internal.R.styleable.ExtendAnimation_toExtendTop), context);
mToTopType = d.type;
mToTopValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ExtendAnimation_toExtendRight));
+ com.android.internal.R.styleable.ExtendAnimation_toExtendRight), context);
mToRightType = d.type;
mToRightValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ExtendAnimation_toExtendBottom));
+ com.android.internal.R.styleable.ExtendAnimation_toExtendBottom), context);
mToBottomType = d.type;
mToBottomValue = d.value;
diff --git a/core/java/android/view/animation/GridLayoutAnimationController.java b/core/java/android/view/animation/GridLayoutAnimationController.java
index 0f189ae98030..c77f54fa889e 100644
--- a/core/java/android/view/animation/GridLayoutAnimationController.java
+++ b/core/java/android/view/animation/GridLayoutAnimationController.java
@@ -116,10 +116,12 @@ public class GridLayoutAnimationController extends LayoutAnimationController {
com.android.internal.R.styleable.GridLayoutAnimation);
Animation.Description d = Animation.Description.parseValue(
- a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_columnDelay));
+ a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_columnDelay),
+ context);
mColumnDelay = d.value;
d = Animation.Description.parseValue(
- a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_rowDelay));
+ a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_rowDelay),
+ context);
mRowDelay = d.value;
//noinspection PointlessBitwiseExpression
mDirection = a.getInt(com.android.internal.R.styleable.GridLayoutAnimation_direction,
diff --git a/core/java/android/view/animation/LayoutAnimationController.java b/core/java/android/view/animation/LayoutAnimationController.java
index e2b7519b1912..1d56d293e7df 100644
--- a/core/java/android/view/animation/LayoutAnimationController.java
+++ b/core/java/android/view/animation/LayoutAnimationController.java
@@ -106,7 +106,7 @@ public class LayoutAnimationController {
TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LayoutAnimation);
Animation.Description d = Animation.Description.parseValue(
- a.peekValue(com.android.internal.R.styleable.LayoutAnimation_delay));
+ a.peekValue(com.android.internal.R.styleable.LayoutAnimation_delay), context);
mDelay = d.value;
mOrder = a.getInt(com.android.internal.R.styleable.LayoutAnimation_animationOrder, ORDER_NORMAL);
diff --git a/core/java/android/view/animation/RotateAnimation.java b/core/java/android/view/animation/RotateAnimation.java
index 3c325d9b2aa9..0613cd2ea5ad 100644
--- a/core/java/android/view/animation/RotateAnimation.java
+++ b/core/java/android/view/animation/RotateAnimation.java
@@ -56,12 +56,12 @@ public class RotateAnimation extends Animation {
mToDegrees = a.getFloat(com.android.internal.R.styleable.RotateAnimation_toDegrees, 0.0f);
Description d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.RotateAnimation_pivotX));
+ com.android.internal.R.styleable.RotateAnimation_pivotX), context);
mPivotXType = d.type;
mPivotXValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.RotateAnimation_pivotY));
+ com.android.internal.R.styleable.RotateAnimation_pivotY), context);
mPivotYType = d.type;
mPivotYValue = d.value;
diff --git a/core/java/android/view/animation/ScaleAnimation.java b/core/java/android/view/animation/ScaleAnimation.java
index e9a84364452c..533ef45e7fe5 100644
--- a/core/java/android/view/animation/ScaleAnimation.java
+++ b/core/java/android/view/animation/ScaleAnimation.java
@@ -118,12 +118,12 @@ public class ScaleAnimation extends Animation {
}
Description d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ScaleAnimation_pivotX));
+ com.android.internal.R.styleable.ScaleAnimation_pivotX), context);
mPivotXType = d.type;
mPivotXValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.ScaleAnimation_pivotY));
+ com.android.internal.R.styleable.ScaleAnimation_pivotY), context);
mPivotYType = d.type;
mPivotYValue = d.value;
diff --git a/core/java/android/view/animation/TranslateAnimation.java b/core/java/android/view/animation/TranslateAnimation.java
index 3365c70b5b34..e27469c0729a 100644
--- a/core/java/android/view/animation/TranslateAnimation.java
+++ b/core/java/android/view/animation/TranslateAnimation.java
@@ -73,22 +73,22 @@ public class TranslateAnimation extends Animation {
com.android.internal.R.styleable.TranslateAnimation);
Description d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.TranslateAnimation_fromXDelta));
+ com.android.internal.R.styleable.TranslateAnimation_fromXDelta), context);
mFromXType = d.type;
mFromXValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.TranslateAnimation_toXDelta));
+ com.android.internal.R.styleable.TranslateAnimation_toXDelta), context);
mToXType = d.type;
mToXValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.TranslateAnimation_fromYDelta));
+ com.android.internal.R.styleable.TranslateAnimation_fromYDelta), context);
mFromYType = d.type;
mFromYValue = d.value;
d = Description.parseValue(a.peekValue(
- com.android.internal.R.styleable.TranslateAnimation_toYDelta));
+ com.android.internal.R.styleable.TranslateAnimation_toYDelta), context);
mToYType = d.type;
mToYValue = d.value;
diff --git a/core/java/android/window/BackNavigationInfo.java b/core/java/android/window/BackNavigationInfo.java
index 571714cc05d5..18c20e2b1fa5 100644
--- a/core/java/android/window/BackNavigationInfo.java
+++ b/core/java/android/window/BackNavigationInfo.java
@@ -16,8 +16,6 @@
package android.window;
-import static java.util.Objects.requireNonNull;
-
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -61,6 +59,12 @@ public final class BackNavigationInfo implements Parcelable {
public static final int TYPE_CROSS_TASK = 3;
/**
+ * A {@link android.view.OnBackInvokedCallback} is available and needs to be called.
+ * <p>
+ */
+ public static final int TYPE_CALLBACK = 4;
+
+ /**
* Defines the type of back destinations a back even can lead to. This is used to define the
* type of animation that need to be run on SystemUI.
*/
@@ -84,35 +88,39 @@ public final class BackNavigationInfo implements Parcelable {
private final RemoteCallback mRemoteCallback;
@Nullable
private final WindowConfiguration mTaskWindowConfiguration;
+ @Nullable
+ private final IOnBackInvokedCallback mOnBackInvokedCallback;
/**
* Create a new {@link BackNavigationInfo} instance.
*
- * @param type The {@link BackTargetType} of the destination (what will be displayed after
- * the back action)
- * @param topWindowLeash The leash to animate away the current topWindow. The consumer
- * of the leash is responsible for removing it.
- * @param screenshotSurface The screenshot of the previous activity to be displayed.
- * @param screenshotBuffer A buffer containing a screenshot used to display the activity.
- * See {@link #getScreenshotHardwareBuffer()} for information
- * about nullity.
- * @param taskWindowConfiguration The window configuration of the Task being animated
- * beneath.
- * @param onBackNavigationDone The callback to be called once the client is done with the back
- * preview.
+ * @param type The {@link BackTargetType} of the destination (what will be
+ * displayed after the back action).
+ * @param topWindowLeash The leash to animate away the current topWindow. The consumer
+ * of the leash is responsible for removing it.
+ * @param screenshotSurface The screenshot of the previous activity to be displayed.
+ * @param screenshotBuffer A buffer containing a screenshot used to display the activity.
+ * See {@link #getScreenshotHardwareBuffer()} for information
+ * about nullity.
+ * @param taskWindowConfiguration The window configuration of the Task being animated beneath.
+ * @param onBackNavigationDone The callback to be called once the client is done with the
+ * back preview.
+ * @param onBackInvokedCallback The back callback registered by the current top level window.
*/
public BackNavigationInfo(@BackTargetType int type,
@Nullable SurfaceControl topWindowLeash,
@Nullable SurfaceControl screenshotSurface,
@Nullable HardwareBuffer screenshotBuffer,
@Nullable WindowConfiguration taskWindowConfiguration,
- @NonNull RemoteCallback onBackNavigationDone) {
+ @Nullable RemoteCallback onBackNavigationDone,
+ @Nullable IOnBackInvokedCallback onBackInvokedCallback) {
mType = type;
mDepartingWindowContainer = topWindowLeash;
mScreenshotSurface = screenshotSurface;
mScreenshotBuffer = screenshotBuffer;
mTaskWindowConfiguration = taskWindowConfiguration;
mRemoteCallback = onBackNavigationDone;
+ mOnBackInvokedCallback = onBackInvokedCallback;
}
private BackNavigationInfo(@NonNull Parcel in) {
@@ -121,7 +129,8 @@ public final class BackNavigationInfo implements Parcelable {
mScreenshotSurface = in.readTypedObject(SurfaceControl.CREATOR);
mScreenshotBuffer = in.readTypedObject(HardwareBuffer.CREATOR);
mTaskWindowConfiguration = in.readTypedObject(WindowConfiguration.CREATOR);
- mRemoteCallback = requireNonNull(in.readTypedObject(RemoteCallback.CREATOR));
+ mRemoteCallback = in.readTypedObject(RemoteCallback.CREATOR);
+ mOnBackInvokedCallback = IOnBackInvokedCallback.Stub.asInterface(in.readStrongBinder());
}
@Override
@@ -132,10 +141,12 @@ public final class BackNavigationInfo implements Parcelable {
dest.writeTypedObject(mScreenshotBuffer, flags);
dest.writeTypedObject(mTaskWindowConfiguration, flags);
dest.writeTypedObject(mRemoteCallback, flags);
+ dest.writeStrongInterface(mOnBackInvokedCallback);
}
/**
* Returns the type of back navigation that is about to happen.
+ *
* @see BackTargetType
*/
public @BackTargetType int getType() {
@@ -152,8 +163,8 @@ public final class BackNavigationInfo implements Parcelable {
}
/**
- * Returns the {@link SurfaceControl} that should be used to display a screenshot of the
- * previous activity.
+ * Returns the {@link SurfaceControl} that should be used to display a screenshot of the
+ * previous activity.
*/
@Nullable
public SurfaceControl getScreenshotSurface() {
@@ -185,11 +196,27 @@ public final class BackNavigationInfo implements Parcelable {
}
/**
+ * Returns the {@link android.view.OnBackInvokedCallback} of the top level window or null if
+ * the client didn't register a callback.
+ * <p>
+ * This is never null when {@link #getType} returns {@link #TYPE_CALLBACK}.
+ *
+ * @see android.view.OnBackInvokedCallback
+ * @see android.view.OnBackInvokedDispatcher
+ */
+ @Nullable
+ public IOnBackInvokedCallback getOnBackInvokedCallback() {
+ return mOnBackInvokedCallback;
+ }
+
+ /**
* Callback to be called when the back preview is finished in order to notify the server that
* it can clean up the resources created for the animation.
*/
public void onBackNavigationFinished() {
- mRemoteCallback.sendResult(null);
+ if (mRemoteCallback != null) {
+ mRemoteCallback.sendResult(null);
+ }
}
@Override
@@ -218,6 +245,7 @@ public final class BackNavigationInfo implements Parcelable {
+ ", mTaskWindowConfiguration= " + mTaskWindowConfiguration
+ ", mScreenshotBuffer=" + mScreenshotBuffer
+ ", mRemoteCallback=" + mRemoteCallback
+ + ", mOnBackInvokedCallback=" + mOnBackInvokedCallback
+ '}';
}
@@ -226,7 +254,7 @@ public final class BackNavigationInfo implements Parcelable {
*/
public static String typeToString(@BackTargetType int type) {
switch (type) {
- case TYPE_UNDEFINED:
+ case TYPE_UNDEFINED:
return "TYPE_UNDEFINED";
case TYPE_DIALOG_CLOSE:
return "TYPE_DIALOG_CLOSE";
diff --git a/core/java/android/window/ProxyOnBackInvokedDispatcher.java b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
new file mode 100644
index 000000000000..509bbd4de389
--- /dev/null
+++ b/core/java/android/window/ProxyOnBackInvokedDispatcher.java
@@ -0,0 +1,162 @@
+/*
+ * 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.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+import android.util.Pair;
+import android.view.OnBackInvokedCallback;
+import android.view.OnBackInvokedDispatcher;
+import android.view.OnBackInvokedDispatcherOwner;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@link OnBackInvokedDispatcher} only used to hold callbacks while an actual
+ * dispatcher becomes available. <b>It does not dispatch the back events</b>.
+ * <p>
+ * Once the actual {@link OnBackInvokedDispatcherOwner} becomes available,
+ * {@link #setActualDispatcherOwner(OnBackInvokedDispatcherOwner)} needs to
+ * be called and this {@link ProxyOnBackInvokedDispatcher} will pass the callback registrations
+ * onto it.
+ * <p>
+ * This dispatcher will continue to keep track of callback registrations and when a dispatcher is
+ * removed or set it will unregister the callbacks from the old one and register them on the new
+ * one unless {@link #reset()} is called before.
+ *
+ * @hide
+ */
+public class ProxyOnBackInvokedDispatcher extends OnBackInvokedDispatcher {
+
+ /**
+ * List of pair representing an {@link OnBackInvokedCallback} and its associated priority.
+ *
+ * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(OnBackInvokedCallback, int)
+ */
+ private final List<Pair<OnBackInvokedCallback, Integer>> mCallbacks = new ArrayList<>();
+ private final Object mLock = new Object();
+ private OnBackInvokedDispatcherOwner mActualDispatcherOwner = null;
+
+ @Override
+ public void registerOnBackInvokedCallback(
+ @NonNull OnBackInvokedCallback callback, int priority) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("Pending register %s. Actual=%s", callback,
+ mActualDispatcherOwner));
+ }
+ synchronized (mLock) {
+ mCallbacks.add(Pair.create(callback, priority));
+ if (mActualDispatcherOwner != null) {
+ mActualDispatcherOwner.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ callback, priority);
+ }
+
+ }
+ }
+
+ @Override
+ public void unregisterOnBackInvokedCallback(
+ @NonNull OnBackInvokedCallback callback) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("Pending unregister %s. Actual=%s", callback,
+ mActualDispatcherOwner));
+ }
+ synchronized (mLock) {
+ mCallbacks.removeIf((p) -> p.first.equals(callback));
+ }
+ }
+
+ /**
+ * Transfers all the pending callbacks to the provided dispatcher.
+ * <p>
+ * The callbacks are registered on the dispatcher in the same order as they were added on this
+ * proxy dispatcher.
+ */
+ private void transferCallbacksToDispatcher() {
+ if (mActualDispatcherOwner == null) {
+ return;
+ }
+ OnBackInvokedDispatcher dispatcher =
+ mActualDispatcherOwner.getOnBackInvokedDispatcher();
+ if (DEBUG) {
+ Log.v(TAG, String.format("Pending transferring %d callbacks to %s", mCallbacks.size(),
+ dispatcher));
+ }
+ for (Pair<OnBackInvokedCallback, Integer> callbackPair : mCallbacks) {
+ dispatcher.registerOnBackInvokedCallback(callbackPair.first,
+ callbackPair.second);
+ }
+ mCallbacks.clear();
+ }
+
+ private void clearCallbacksOnDispatcher() {
+ if (mActualDispatcherOwner == null) {
+ return;
+ }
+ OnBackInvokedDispatcher onBackInvokedDispatcher =
+ mActualDispatcherOwner.getOnBackInvokedDispatcher();
+ for (Pair<OnBackInvokedCallback, Integer> callback : mCallbacks) {
+ onBackInvokedDispatcher.unregisterOnBackInvokedCallback(callback.first);
+ }
+ }
+
+ /**
+ * Resets this {@link ProxyOnBackInvokedDispatcher} so it loses track of the currently
+ * registered callbacks.
+ * <p>
+ * Using this method means that when setting a new {@link OnBackInvokedDispatcherOwner}, the
+ * callbacks registered on the old one won't be removed from it and won't be registered on
+ * the new one.
+ */
+ public void reset() {
+ if (DEBUG) {
+ Log.v(TAG, "Pending reset callbacks");
+ }
+ synchronized (mLock) {
+ mCallbacks.clear();
+ }
+ }
+
+ /**
+ * Sets the actual {@link OnBackInvokedDispatcherOwner} that will provides the
+ * {@link OnBackInvokedDispatcher} onto which the callbacks will be registered.
+ * <p>
+ * If any dispatcher owner was already present, all the callbacks that were added via this
+ * {@link ProxyOnBackInvokedDispatcher} will be unregistered from the old one and registered
+ * on the new one if it is not null.
+ * <p>
+ * If you do not wish for the previously registered callbacks to be reassigned to the new
+ * dispatcher, {@link #reset} must be called beforehand.
+ */
+ public void setActualDispatcherOwner(
+ @Nullable OnBackInvokedDispatcherOwner actualDispatcherOwner) {
+ if (DEBUG) {
+ Log.v(TAG, String.format("Pending setActual %s. Current %s",
+ actualDispatcherOwner, mActualDispatcherOwner));
+ }
+ synchronized (mLock) {
+ if (actualDispatcherOwner == mActualDispatcherOwner) {
+ return;
+ }
+ clearCallbacksOnDispatcher();
+ mActualDispatcherOwner = actualDispatcherOwner;
+ transferCallbacksToDispatcher();
+ }
+ }
+}
diff --git a/core/java/com/android/internal/app/BlockedAppActivity.java b/core/java/com/android/internal/app/BlockedAppActivity.java
index 65526eba3e54..fbdbbfb06b78 100644
--- a/core/java/com/android/internal/app/BlockedAppActivity.java
+++ b/core/java/com/android/internal/app/BlockedAppActivity.java
@@ -17,7 +17,6 @@
package com.android.internal.app;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
@@ -36,9 +35,6 @@ public class BlockedAppActivity extends AlertActivity {
private static final String TAG = "BlockedAppActivity";
private static final String PACKAGE_NAME = "com.android.internal.app";
private static final String EXTRA_BLOCKED_PACKAGE = PACKAGE_NAME + ".extra.BLOCKED_PACKAGE";
- private static final String EXTRA_BLOCKED_ACTIVITY_INFO =
- PACKAGE_NAME + ".extra.BLOCKED_ACTIVITY_INFO";
- private static final String EXTRA_STREAMED_DEVICE = PACKAGE_NAME + ".extra.STREAMED_DEVICE";
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -52,30 +48,17 @@ public class BlockedAppActivity extends AlertActivity {
return;
}
- CharSequence appLabel = null;
String packageName = intent.getStringExtra(EXTRA_BLOCKED_PACKAGE);
- ActivityInfo activityInfo = intent.getParcelableExtra(EXTRA_BLOCKED_ACTIVITY_INFO);
- if (activityInfo != null) {
- appLabel = activityInfo.loadLabel(getPackageManager());
- } else if (!TextUtils.isEmpty(packageName)) {
- appLabel = getAppLabel(userId, packageName);
- }
-
- if (TextUtils.isEmpty(appLabel)) {
- Slog.wtf(TAG, "Invalid package: " + packageName + " or activity info: " + activityInfo);
+ if (TextUtils.isEmpty(packageName)) {
+ Slog.wtf(TAG, "Invalid package: " + packageName);
finish();
return;
}
- CharSequence streamedDeviceName = intent.getCharSequenceExtra(EXTRA_STREAMED_DEVICE);
- if (!TextUtils.isEmpty(streamedDeviceName)) {
- mAlertParams.mTitle = getString(R.string.app_streaming_blocked_title, appLabel);
- mAlertParams.mMessage =
- getString(R.string.app_streaming_blocked_message, streamedDeviceName);
- } else {
- mAlertParams.mTitle = getString(R.string.app_blocked_title);
- mAlertParams.mMessage = getString(R.string.app_blocked_message, appLabel);
- }
+ CharSequence appLabel = getAppLabel(userId, packageName);
+
+ mAlertParams.mTitle = getString(R.string.app_blocked_title);
+ mAlertParams.mMessage = getString(R.string.app_blocked_message, appLabel);
mAlertParams.mPositiveButtonText = getString(android.R.string.ok);
setupAlert();
}
@@ -100,19 +83,4 @@ public class BlockedAppActivity extends AlertActivity {
.putExtra(Intent.EXTRA_USER_ID, userId)
.putExtra(EXTRA_BLOCKED_PACKAGE, packageName);
}
-
- /**
- * Creates an intent that launches {@link BlockedAppActivity} when app streaming is blocked.
- *
- * Using this method and providing a non-empty {@code streamedDeviceName} will cause the dialog
- * to use streaming-specific error messages.
- */
- public static Intent createStreamingBlockedIntent(int userId, ActivityInfo activityInfo,
- CharSequence streamedDeviceName) {
- return new Intent()
- .setClassName("android", BlockedAppActivity.class.getName())
- .putExtra(Intent.EXTRA_USER_ID, userId)
- .putExtra(EXTRA_BLOCKED_ACTIVITY_INFO, activityInfo)
- .putExtra(EXTRA_STREAMED_DEVICE, streamedDeviceName);
- }
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index c0fec62bdd94..5ba45c9b8bc3 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -607,11 +607,15 @@ public class BatteryStatsImpl extends BatteryStats {
int UPDATE_BT = 0x08;
int UPDATE_RPM = 0x10;
int UPDATE_DISPLAY = 0x20;
+ int RESET = 0x40;
+
int UPDATE_ALL =
UPDATE_CPU | UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT | UPDATE_RPM | UPDATE_DISPLAY;
int UPDATE_ON_PROC_STATE_CHANGE = UPDATE_WIFI | UPDATE_RADIO | UPDATE_BT;
+ int UPDATE_ON_RESET = UPDATE_ALL | RESET;
+
@IntDef(flag = true, prefix = "UPDATE_", value = {
UPDATE_CPU,
UPDATE_WIFI,
@@ -12909,7 +12913,7 @@ public class BatteryStatsImpl extends BatteryStats {
// Flush external data, gathering snapshots, but don't process it since it is pre-reset data
mIgnoreNextExternalStats = true;
- mExternalSync.scheduleSync("reset", ExternalStatsSync.UPDATE_ALL);
+ mExternalSync.scheduleSync("reset", ExternalStatsSync.UPDATE_ON_RESET);
mHandler.sendEmptyMessage(MSG_REPORT_RESET_STATS);
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 2925341cd948..40e40856b000 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -87,7 +87,6 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
-import android.view.OnBackInvokedDispatcher;
import android.view.PendingInsetsController;
import android.view.ThreadedRenderer;
import android.view.View;
@@ -109,7 +108,6 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.PopupWindow;
-import android.window.WindowOnBackInvokedDispatcher;
import com.android.internal.R;
import com.android.internal.graphics.drawable.BackgroundBlurDrawable;
@@ -297,7 +295,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
return true;
};
private Consumer<Boolean> mCrossWindowBlurEnabledListener;
- private final WindowOnBackInvokedDispatcher mOnBackInvokedDispatcher;
DecorView(Context context, int featureId, PhoneWindow window,
WindowManager.LayoutParams params) {
@@ -326,7 +323,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
initResizingPaints();
mLegacyNavigationBarBackgroundPaint.setColor(Color.BLACK);
- mOnBackInvokedDispatcher = new WindowOnBackInvokedDispatcher();
}
void setBackgroundFallback(@Nullable Drawable fallbackDrawable) {
@@ -1880,7 +1876,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
mPendingInsetsController.detach();
- mOnBackInvokedDispatcher.detachFromWindow();
}
@Override
@@ -1925,11 +1920,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
return mPendingInsetsController;
}
- @Override
- public WindowOnBackInvokedDispatcher provideWindowOnBackInvokedDispatcher() {
- return mOnBackInvokedDispatcher;
- }
-
private ActionMode createActionMode(
int type, ActionMode.Callback2 callback, View originatingView) {
switch (type) {
@@ -2384,7 +2374,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
}
}
- mOnBackInvokedDispatcher.clear();
}
@Override
@@ -2666,15 +2655,6 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
}
- /**
- * Returns the {@link OnBackInvokedDispatcher} on the decor view.
- */
- @Override
- @Nullable
- public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
- return mOnBackInvokedDispatcher;
- }
-
@Override
public String toString() {
return "DecorView@" + Integer.toHexString(this.hashCode()) + "["
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 7755b694af03..12f38a4d5b9a 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -91,6 +91,8 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
+import android.view.OnBackInvokedDispatcher;
+import android.view.OnBackInvokedDispatcherOwner;
import android.view.ScrollCaptureCallback;
import android.view.SearchEvent;
import android.view.SurfaceHolder.Callback2;
@@ -110,6 +112,7 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
+import android.window.ProxyOnBackInvokedDispatcher;
import com.android.internal.R;
import com.android.internal.view.menu.ContextMenuBuilder;
@@ -134,7 +137,8 @@ import java.util.List;
*
* @hide
*/
-public class PhoneWindow extends Window implements MenuBuilder.Callback {
+public class PhoneWindow extends Window implements MenuBuilder.Callback,
+ OnBackInvokedDispatcherOwner {
private final static String TAG = "PhoneWindow";
@@ -340,6 +344,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
boolean mDecorFitsSystemWindows = true;
+ private ProxyOnBackInvokedDispatcher mProxyOnBackInvokedDispatcher =
+ new ProxyOnBackInvokedDispatcher();
+
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"));
@@ -2146,6 +2153,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
/** Notify when decor view is attached to window and {@link ViewRootImpl} is available. */
void onViewRootImplSet(ViewRootImpl viewRoot) {
viewRoot.setActivityConfigCallback(mActivityConfigCallback);
+ mProxyOnBackInvokedDispatcher.setActualDispatcherOwner(viewRoot);
applyDecorFitsSystemWindows();
}
@@ -3993,4 +4001,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
public AttachedSurfaceControl getRootSurfaceControl() {
return getViewRootImplOrNull();
}
+
+ @NonNull
+ @Override
+ public OnBackInvokedDispatcher getOnBackInvokedDispatcher() {
+ return mProxyOnBackInvokedDispatcher;
+ }
}
diff --git a/core/java/com/android/internal/power/MeasuredEnergyStats.java b/core/java/com/android/internal/power/MeasuredEnergyStats.java
index a52ae107d983..7262e846d9b0 100644
--- a/core/java/com/android/internal/power/MeasuredEnergyStats.java
+++ b/core/java/com/android/internal/power/MeasuredEnergyStats.java
@@ -438,10 +438,16 @@ public class MeasuredEnergyStats {
mState = state;
mStateChangeTimestampMs = timestampMs;
if (mAccumulatedMultiStateChargeMicroCoulomb == null) {
- return;
+ mAccumulatedMultiStateChargeMicroCoulomb =
+ new LongMultiStateCounter[mAccumulatedChargeMicroCoulomb.length];
}
for (int i = 0; i < mAccumulatedMultiStateChargeMicroCoulomb.length; i++) {
LongMultiStateCounter counter = mAccumulatedMultiStateChargeMicroCoulomb[i];
+ if (counter == null && mConfig.isSupportedMultiStateBucket(i)) {
+ counter = new LongMultiStateCounter(mConfig.mStateNames.length);
+ counter.updateValue(0, timestampMs);
+ mAccumulatedMultiStateChargeMicroCoulomb[i] = counter;
+ }
if (counter != null) {
counter.setState(state, timestampMs);
}
diff --git a/core/java/com/android/internal/view/RootViewSurfaceTaker.java b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
index 4b89bf5082ba..3ab9a335c8b7 100644
--- a/core/java/com/android/internal/view/RootViewSurfaceTaker.java
+++ b/core/java/com/android/internal/view/RootViewSurfaceTaker.java
@@ -15,12 +15,10 @@
*/
package com.android.internal.view;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.view.InputQueue;
import android.view.PendingInsetsController;
import android.view.SurfaceHolder;
-import android.window.WindowOnBackInvokedDispatcher;
/** hahahah */
public interface RootViewSurfaceTaker {
@@ -31,6 +29,4 @@ public interface RootViewSurfaceTaker {
InputQueue.Callback willYouTakeTheInputQueue();
void onRootViewScrollYChanged(int scrollY);
@Nullable PendingInsetsController providePendingInsetsController();
- /** @hide */
- @NonNull WindowOnBackInvokedDispatcher provideWindowOnBackInvokedDispatcher();
}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index edc8c5b99ebe..2bec733d954c 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -18,25 +18,25 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioSystem-JNI"
-#include <utils/Log.h>
-
-#include <sstream>
-#include <vector>
-#include <jni.h>
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-
#include <android/media/AudioVibratorInfo.h>
#include <android/media/INativeSpatializerCallback.h>
#include <android/media/ISpatializer.h>
+#include <android_os_Parcel.h>
#include <audiomanager/AudioManager.h>
+#include <jni.h>
#include <media/AudioContainers.h>
#include <media/AudioPolicy.h>
#include <media/AudioSystem.h>
#include <media/MicrophoneInfo.h>
+#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedLocalRef.h>
#include <system/audio.h>
#include <system/audio_policy.h>
+#include <utils/Log.h>
+
+#include <sstream>
+#include <vector>
+
#include "android_media_AudioAttributes.h"
#include "android_media_AudioDescriptor.h"
#include "android_media_AudioDeviceAttributes.h"
@@ -46,6 +46,7 @@
#include "android_media_AudioProfile.h"
#include "android_media_MicrophoneInfo.h"
#include "android_util_Binder.h"
+#include "core_jni_helpers.h"
// ----------------------------------------------------------------------------
@@ -584,18 +585,26 @@ android_media_AudioSystem_routing_callback()
env->DeleteLocalRef(clazz);
}
-static jint
-android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name,
- jint codec)
-{
- const char *c_address = env->GetStringUTFChars(device_address, NULL);
- const char *c_name = env->GetStringUTFChars(device_name, NULL);
- int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
- static_cast <audio_policy_dev_state_t>(state),
- c_address, c_name,
- static_cast <audio_format_t>(codec)));
- env->ReleaseStringUTFChars(device_address, c_address);
- env->ReleaseStringUTFChars(device_name, c_name);
+static jint android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz,
+ jint state, jobject jParcel,
+ jint codec) {
+ int status;
+ if (Parcel *parcel = parcelForJavaObject(env, jParcel); parcel != nullptr) {
+ android::media::audio::common::AudioPort port{};
+ if (status_t statusOfParcel = port.readFromParcel(parcel); statusOfParcel == OK) {
+ status = check_AudioSystem_Command(
+ AudioSystem::setDeviceConnectionState(static_cast<audio_policy_dev_state_t>(
+ state),
+ port,
+ static_cast<audio_format_t>(codec)));
+ } else {
+ ALOGE("Failed to read from parcel: %s", statusToString(statusOfParcel).c_str());
+ status = kAudioStatusError;
+ }
+ } else {
+ ALOGE("Failed to retrieve the native parcel from Java parcel");
+ status = kAudioStatusError;
+ }
return (jint) status;
}
@@ -2912,7 +2921,7 @@ static const JNINativeMethod gMethods[] =
{"newAudioSessionId", "()I", (void *)android_media_AudioSystem_newAudioSessionId},
{"newAudioPlayerId", "()I", (void *)android_media_AudioSystem_newAudioPlayerId},
{"newAudioRecorderId", "()I", (void *)android_media_AudioSystem_newAudioRecorderId},
- {"setDeviceConnectionState", "(IILjava/lang/String;Ljava/lang/String;I)I",
+ {"setDeviceConnectionState", "(ILandroid/os/Parcel;I)I",
(void *)android_media_AudioSystem_setDeviceConnectionState},
{"getDeviceConnectionState", "(ILjava/lang/String;)I",
(void *)android_media_AudioSystem_getDeviceConnectionState},
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 7c67cbcbd23c..a6fbf094a030 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -235,9 +235,7 @@ void android_os_Process_setThreadGroupAndCpuset(JNIEnv* env, jobject clazz, int
void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
{
ALOGV("%s pid=%d grp=%" PRId32, __func__, pid, grp);
- DIR *d;
char proc_path[255];
- struct dirent *de;
if (!verifyGroup(env, grp)) {
return;
@@ -277,84 +275,8 @@ void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jin
}
}
- sprintf(proc_path, "/proc/%d/task", pid);
- if (!(d = opendir(proc_path))) {
- // If the process exited on us, don't generate an exception
- if (errno != ENOENT)
- signalExceptionForGroupError(env, errno, pid);
- return;
- }
-
- while ((de = readdir(d))) {
- int t_pid;
- int t_pri;
- std::string taskprofile;
-
- if (de->d_name[0] == '.')
- continue;
- t_pid = atoi(de->d_name);
-
- if (!t_pid) {
- ALOGE("Error getting pid for '%s'\n", de->d_name);
- continue;
- }
-
- t_pri = getpriority(PRIO_PROCESS, t_pid);
-
- if (t_pri <= ANDROID_PRIORITY_AUDIO) {
- int scheduler = sched_getscheduler(t_pid) & ~SCHED_RESET_ON_FORK;
- if ((scheduler == SCHED_FIFO) || (scheduler == SCHED_RR)) {
- // This task wants to stay in its current audio group so it can keep its budget
- // don't update its cpuset or cgroup
- continue;
- }
- }
-
- errno = 0;
- // grp == SP_BACKGROUND. Set background cpuset policy profile for all threads.
- if (grp == SP_BACKGROUND) {
- if (!SetTaskProfiles(t_pid, {"CPUSET_SP_BACKGROUND"}, true)) {
- signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
- break;
- }
- continue;
- }
-
- // grp != SP_BACKGROUND. Only change the cpuset cgroup for low priority thread, so it could
- // preserve it sched policy profile setting.
- if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
- switch (grp) {
- case SP_SYSTEM:
- taskprofile = "ServiceCapacityLow";
- break;
- case SP_RESTRICTED:
- taskprofile = "ServiceCapacityRestricted";
- break;
- case SP_FOREGROUND:
- case SP_AUDIO_APP:
- case SP_AUDIO_SYS:
- taskprofile = "ProcessCapacityHigh";
- break;
- case SP_TOP_APP:
- taskprofile = "ProcessCapacityMax";
- break;
- default:
- taskprofile = "ProcessCapacityNormal";
- break;
- }
- if (!SetTaskProfiles(t_pid, {taskprofile}, true)) {
- signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
- break;
- }
- // Change the cpuset policy profile for non-low priority thread according to the grp
- } else {
- if (!SetTaskProfiles(t_pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}, true)) {
- signalExceptionForGroupError(env, errno ? errno : EPERM, t_pid);
- break;
- }
- }
- }
- closedir(d);
+ if (!SetProcessProfilesCached(0, pid, {get_cpuset_policy_profile_name((SchedPolicy)grp)}))
+ signalExceptionForGroupError(env, errno ? errno : EPERM, pid);
}
void android_os_Process_setProcessFrozen(
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index d48ea3b8785c..04f4d7b09d82 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -452,16 +452,16 @@ message LowPowerStandbyControllerDumpProto {
optional bool is_interactive = 5;
// Time (in elapsedRealtime) when the device was last interactive
- optional bool last_interactive_time = 6;
+ optional int64 last_interactive_time = 6;
- // Time (in milliseconds) after becoming non-interactive that Low Power Standby can activate
+ // Timeout (in milliseconds) after becoming non-interactive that Low Power Standby can activate
optional int32 standby_timeout_config = 7;
// True if the device has entered idle mode since becoming non-interactive
- optional int32 idle_since_non_interactive = 8;
+ optional bool idle_since_non_interactive = 8;
// True if the device is currently in idle mode
- optional int32 is_device_idle = 9;
+ optional bool is_device_idle = 9;
// Set of app ids that are exempt form low power standby
repeated int32 allowlist = 10;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 85504ceae791..506a0c09b7c9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -398,6 +398,7 @@
<protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
<protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED" />
+ <protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_RESOURCE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED" />
<protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
<protected-broadcast android:name="android.net.wifi.RSSI_CHANGED" />
@@ -2027,6 +2028,11 @@
<permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE"
android:protectionLevel="signature" />
+ <!-- @SystemApi @hide Allows an application to manage ethernet networks.
+ <p>Not for use by third-party or privileged applications. -->
+ <permission android:name="android.permission.MANAGE_ETHERNET_NETWORKS"
+ android:protectionLevel="signature" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
@@ -6540,12 +6546,27 @@
android:exported="false">
</activity>
+ <activity android:name="com.android.server.logcat.LogAccessConfirmationActivity"
+ android:theme="@style/Theme.Dialog.Confirmation"
+ android:excludeFromRecents="true"
+ android:process=":ui"
+ android:label="@string/log_access_confirmation_title"
+ android:exported="false">
+ </activity>
+
<activity android:name="com.android.server.notification.NASLearnMoreActivity"
android:theme="@style/Theme.Dialog.Confirmation"
android:excludeFromRecents="true"
android:exported="false">
</activity>
+ <activity android:name="android.service.games.GameSessionTrampolineActivity"
+ android:excludeFromRecents="true"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_GAME_ACTIVITY"
+ android:theme="@style/Theme.Translucent.NoTitleBar">
+ </activity>
+
<receiver android:name="com.android.server.BootReceiver"
android:exported="true"
android:systemUserOnly="true">
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index afe0f1bf0001..d774fd4e397a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6953,10 +6953,10 @@
</declare-styleable>
<declare-styleable name="TranslateAnimation">
- <attr name="fromXDelta" format="float|fraction" />
- <attr name="toXDelta" format="float|fraction" />
- <attr name="fromYDelta" format="float|fraction" />
- <attr name="toYDelta" format="float|fraction" />
+ <attr name="fromXDelta" format="float|fraction|dimension" />
+ <attr name="toXDelta" format="float|fraction|dimension" />
+ <attr name="fromYDelta" format="float|fraction|dimension" />
+ <attr name="toYDelta" format="float|fraction|dimension" />
</declare-styleable>
<declare-styleable name="AlphaAnimation">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 52c62050f6a1..d7ebb0f18c4b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5439,15 +5439,6 @@
<xliff:g id="app_name" example="Gmail">%1$s</xliff:g> is not available right now.
</string>
- <!-- Title of the dialog shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
- <string name="app_streaming_blocked_title"><xliff:g id="activity" example="Permission dialog">%1$s</xliff:g> unavailable</string>
- <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
- <string name="app_streaming_blocked_message" product="tv">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your Android TV device instead.</string>
- <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
- <string name="app_streaming_blocked_message" product="tablet">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your tablet instead.</string>
- <!-- Message shown when an app is blocked from being streamed to a remote device. [CHAR LIMIT=NONE] -->
- <string name="app_streaming_blocked_message" product="default">This can’t be accessed on your <xliff:g id="device" example="Chromebook">%1$s</xliff:g> at this time. Try on your phone instead.</string>
-
<!-- Message displayed in dialog when app is too old to run on this verison of android. [CHAR LIMIT=NONE] -->
<string name="deprecated_target_sdk_message">This app was built for an older version of Android and may not work properly. Try checking for updates, or contact the developer.</string>
<!-- Title for button to see application detail in app store which it came from - it may allow user to update to newer version. [CHAR LIMIT=50] -->
@@ -5689,6 +5680,20 @@
<!-- Title for the harmful app warning dialog. [CHAR LIMIT=40] -->
<string name="harmful_app_warning_title">Harmful app detected</string>
+ <!-- Title for the log access confirmation dialog. [CHAR LIMIT=40] -->
+ <string name="log_access_confirmation_title">System log access request</string>
+ <!-- Label for the allow button on the log access confirmation dialog. [CHAR LIMIT=20] -->
+ <string name="log_access_confirmation_allow">Only this time</string>
+ <!-- Label for the deny button on the log access confirmation dialog. [CHAR LIMIT=20] -->
+ <string name="log_access_confirmation_deny">Don\u2019t allow</string>
+
+ <!-- Content for the log access confirmation dialog. [CHAR LIMIT=NONE]-->
+ <string name="log_access_confirmation_body"><xliff:g id="log_access_app_name" example="Example App">%s</xliff:g> requests system logs for functional debugging.
+ These logs might contain information that apps and services on your device have written.</string>
+
+ <!-- Privacy notice do not show [CHAR LIMIT=20] -->
+ <string name="log_access_do_not_show_again">Don\u2019t show again</string>
+
<!-- Text describing a permission request for one app to show another app's
slices [CHAR LIMIT=NONE] -->
<string name="slices_permission_request"><xliff:g id="app" example="Example App">%1$s</xliff:g> wants to show <xliff:g id="app_2" example="Other Example App">%2$s</xliff:g> slices</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index facfdb22b91b..33efbce15eea 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3285,9 +3285,6 @@
<java-symbol type="string" name="app_blocked_title" />
<java-symbol type="string" name="app_blocked_message" />
- <java-symbol type="string" name="app_streaming_blocked_title" />
- <java-symbol type="string" name="app_streaming_blocked_message" />
-
<!-- Used internally for assistant to launch activity transitions -->
<java-symbol type="id" name="cross_task_transition" />
@@ -3865,6 +3862,11 @@
<java-symbol type="string" name="harmful_app_warning_title" />
<java-symbol type="layout" name="harmful_app_warning_dialog" />
+ <java-symbol type="string" name="log_access_confirmation_allow" />
+ <java-symbol type="string" name="log_access_confirmation_deny" />
+ <java-symbol type="string" name="log_access_confirmation_title" />
+ <java-symbol type="string" name="log_access_confirmation_body" />
+
<java-symbol type="string" name="config_defaultAssistantAccessComponent" />
<java-symbol type="string" name="slices_permission_request" />
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
index bd987a03b51f..6639c0241ae2 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
@@ -20,6 +20,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.BATTERY_STATS"/>
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
<application
android:theme="@style/Theme"
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
index 02e5942a3544..fc385a013d00 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java
@@ -204,4 +204,6 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon
public void logTrace(long timestamp, String where, long loggingTypes, String callingParams,
int processId, long threadId, int callingUid, Bundle serializedCallingStackInBundle) {}
+
+ public void setAnimationScale(float scale) {}
}
diff --git a/core/tests/coretests/src/android/window/BackNavigationTest.java b/core/tests/coretests/src/android/window/BackNavigationTest.java
new file mode 100644
index 000000000000..91d853143764
--- /dev/null
+++ b/core/tests/coretests/src/android/window/BackNavigationTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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.window;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.NonNull;
+import android.app.ActivityTaskManager;
+import android.app.EmptyActivity;
+import android.app.Instrumentation;
+import android.os.RemoteException;
+import android.support.test.uiautomator.UiDevice;
+import android.view.OnBackInvokedCallback;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Integration test for back navigation
+ */
+public class BackNavigationTest {
+
+ @Rule
+ public final ActivityScenarioRule<EmptyActivity> mScenarioRule =
+ new ActivityScenarioRule<>(EmptyActivity.class);
+ private ActivityScenario<EmptyActivity> mScenario;
+ private Instrumentation mInstrumentation;
+
+ @Before
+ public void setup() {
+ mScenario = mScenarioRule.getScenario();
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ try {
+ UiDevice.getInstance(mInstrumentation).wakeUp();
+ } catch (RemoteException ignored) {
+ }
+ mInstrumentation.getUiAutomation().adoptShellPermissionIdentity();
+ }
+
+ @Test
+ public void registerCallback_initialized() {
+ CountDownLatch latch = registerBackCallback();
+ mScenario.moveToState(Lifecycle.State.RESUMED);
+ assertCallbackIsCalled(latch);
+ }
+
+ @Test
+ public void registerCallback_created() {
+ mScenario.moveToState(Lifecycle.State.CREATED);
+ CountDownLatch latch = registerBackCallback();
+ mScenario.moveToState(Lifecycle.State.STARTED);
+ mScenario.moveToState(Lifecycle.State.RESUMED);
+ assertCallbackIsCalled(latch);
+ }
+
+ @Test
+ public void registerCallback_resumed() {
+ mScenario.moveToState(Lifecycle.State.CREATED);
+ mScenario.moveToState(Lifecycle.State.STARTED);
+ mScenario.moveToState(Lifecycle.State.RESUMED);
+ CountDownLatch latch = registerBackCallback();
+ assertCallbackIsCalled(latch);
+ }
+
+ private void assertCallbackIsCalled(CountDownLatch latch) {
+ try {
+ mInstrumentation.getUiAutomation().waitForIdle(500, 1000);
+ BackNavigationInfo info = ActivityTaskManager.getService().startBackNavigation();
+ assertNotNull("BackNavigationInfo is null", info);
+ assertNotNull("OnBackInvokedCallback is null", info.getOnBackInvokedCallback());
+ info.getOnBackInvokedCallback().onBackInvoked();
+ assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
+ } catch (RemoteException ex) {
+ ex.rethrowFromSystemServer();
+ } catch (InterruptedException ex) {
+ fail("Application died before invoking the callback.\n" + ex.getMessage());
+ } catch (TimeoutException ex) {
+ fail(ex.getMessage());
+ }
+ }
+
+ @NonNull
+ private CountDownLatch registerBackCallback() {
+ CountDownLatch backInvokedLatch = new CountDownLatch(1);
+ CountDownLatch backRegisteredLatch = new CountDownLatch(1);
+ mScenario.onActivity(activity -> {
+ activity.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ new OnBackInvokedCallback() {
+ @Override
+ public void onBackInvoked() {
+ backInvokedLatch.countDown();
+ }
+ }, 0
+ );
+ backRegisteredLatch.countDown();
+ });
+ try {
+ if (!backRegisteredLatch.await(100, TimeUnit.MILLISECONDS)) {
+ fail("Back callback was not registered on the Activity thread. This might be "
+ + "an error with the test itself.");
+ }
+ } catch (InterruptedException e) {
+ fail(e.getMessage());
+ }
+ return backInvokedLatch;
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
index dbb2cf15dd8e..88349b38040c 100644
--- a/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/power/MeasuredEnergyStatsTest.java
@@ -383,10 +383,10 @@ public class MeasuredEnergyStatsTest {
assertEquals(13, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_ON, 0));
// 6 * (6000-4000)/(6000-2000)
assertEquals(3, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_ON, 1));
-
- // POWER_BUCKET_SCREEN_OTHER was only present along with state=1
- assertEquals(0, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_OTHER, 0));
- assertEquals(40, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_OTHER, 1));
+ // 40 * (4000-1000)/(5000-1000)
+ assertEquals(30, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_OTHER, 0));
+ // 40 * (5000-4000)/(5000-1000)
+ assertEquals(10, stats.getAccumulatedStandardBucketCharge(POWER_BUCKET_SCREEN_OTHER, 1));
}
@Test
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index d0026016ecf4..a331b6eb6750 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -474,6 +474,7 @@ applications that come with the platform
<!-- Permission needed for CTS test - WifiManagerTest -->
<permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
<permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
+ <permission name="android.permission.NEARBY_WIFI_DEVICES" />
<permission name="android.permission.OVERRIDE_WIFI_CONFIG" />
<!-- Permission required for CTS test CarrierMessagingServiceWrapperTest -->
<permission name="android.permission.BIND_CARRIER_SERVICES"/>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 15672332a522..f2a875c76f1c 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -727,12 +727,6 @@
"group": "WM_DEBUG_BOOT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-1343787701": {
- "message": "startBackNavigation task=%s, topRunningActivity=%s",
- "level": "DEBUG",
- "group": "WM_DEBUG_BACK_PREVIEW",
- "at": "com\/android\/server\/wm\/BackNavigationController.java"
- },
"-1340540100": {
"message": "Creating SnapshotStartingData",
"level": "VERBOSE",
@@ -1765,6 +1759,12 @@
"group": "WM_DEBUG_SYNC_ENGINE",
"at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
},
+ "-228813488": {
+ "message": "%s: Setting back callback %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/WindowState.java"
+ },
"-208825711": {
"message": "shouldWaitAnimatingExit: isWallpaperTarget: %s",
"level": "DEBUG",
@@ -3691,6 +3691,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/RemoteAnimationController.java"
},
+ "1898905572": {
+ "message": "startBackNavigation task=%s, topRunningActivity=%s, topWindow=%s backCallback=%s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_BACK_PREVIEW",
+ "at": "com\/android\/server\/wm\/BackNavigationController.java"
+ },
"1903353011": {
"message": "notifyAppStopped: %s",
"level": "VERBOSE",
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more.xml
deleted file mode 100644
index ff5740609b84..000000000000
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:fillColor="@android:color/system_neutral2_400"
- android:pathData="M16.59,8.59L12.0,13.17 7.41,8.59 6.0,10.0l6.0,6.0 6.0,-6.0z"/>
-</vector> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more_ripple.xml b/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more_ripple.xml
deleted file mode 100644
index 16dea484b644..000000000000
--- a/libs/WindowManager/Shell/res/drawable/letterbox_education_ic_expand_more_ripple.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@android:color/system_neutral2_200">
- <item android:drawable="@drawable/letterbox_education_ic_expand_more"/>
-</ripple> \ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/letterbox_education_toast_layout.xml b/libs/WindowManager/Shell/res/layout/letterbox_education_toast_layout.xml
deleted file mode 100644
index a309d4829f0d..000000000000
--- a/libs/WindowManager/Shell/res/layout/letterbox_education_toast_layout.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<!--
- ~ 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.
- -->
-<com.android.wm.shell.compatui.LetterboxEduToastLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@color/compat_controls_background"
- android:gravity="center"
- android:paddingVertical="14dp"
- android:paddingHorizontal="16dp">
-
- <!-- Adding an extra layer to animate the alpha of the background and content separately. -->
- <LinearLayout
- android:id="@+id/letterbox_education_content"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/letterbox_education_icon"
- android:layout_width="@dimen/letterbox_education_toast_icon_size"
- android:layout_height="@dimen/letterbox_education_toast_icon_size"/>
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxWidth="@dimen/letterbox_education_toast_text_max_width"
- android:paddingHorizontal="16dp"
- android:lineSpacingExtra="5sp"
- android:text="@string/letterbox_education_toast_title"
- android:textAlignment="viewStart"
- android:textColor="@color/compat_controls_text"
- android:textSize="16sp"
- android:maxLines="1"
- android:ellipsize="end"/>
-
- <ImageButton
- android:id="@+id/letterbox_education_toast_expand"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/letterbox_education_ic_expand_more_ripple"
- android:background="@android:color/transparent"
- android:contentDescription="@string/letterbox_education_expand_button_description"/>
-
- </LinearLayout>
-
-</com.android.wm.shell.compatui.LetterboxEduToastLayout>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index ab2c9b1466b8..40c7647ecedf 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -219,18 +219,9 @@
<!-- The width of the camera compat hint. -->
<dimen name="camera_compat_hint_width">143dp</dimen>
- <!-- The corner radius of the letterbox education toast. -->
- <dimen name="letterbox_education_toast_corner_radius">100dp</dimen>
-
<!-- The corner radius of the letterbox education dialog. -->
<dimen name="letterbox_education_dialog_corner_radius">28dp</dimen>
- <!-- The margin between the letterbox education toast/dialog and the bottom of the task. -->
- <dimen name="letterbox_education_margin_bottom">16dp</dimen>
-
- <!-- The size of the icon in the letterbox education toast. -->
- <dimen name="letterbox_education_toast_icon_size">24dp</dimen>
-
<!-- The size of an icon in the letterbox education dialog. -->
<dimen name="letterbox_education_dialog_icon_size">48dp</dimen>
@@ -243,9 +234,6 @@
<!-- The maximum width of the title and subtitle in the letterbox education dialog. -->
<dimen name="letterbox_education_dialog_title_max_width">444dp</dimen>
- <!-- The maximum width of the text in the letterbox education toast. -->
- <dimen name="letterbox_education_toast_text_max_width">398dp</dimen>
-
<!-- The distance that the letterbox education dialog will move up during appear/dismiss
animation. -->
<dimen name="letterbox_education_dialog_animation_elevation">20dp</dimen>
diff --git a/libs/WindowManager/Shell/res/values/strings.xml b/libs/WindowManager/Shell/res/values/strings.xml
index a8a9ed74cd35..16a4b524803a 100644
--- a/libs/WindowManager/Shell/res/values/strings.xml
+++ b/libs/WindowManager/Shell/res/values/strings.xml
@@ -174,9 +174,6 @@
<!-- The title of the letterbox education dialog. [CHAR LIMIT=NONE] -->
<string name="letterbox_education_dialog_title">Get the most out of <xliff:g id="app_name" example="YouTube">%s</xliff:g></string>
- <!-- The title of the letterbox education toast. [CHAR LIMIT=60] -->
- <string name="letterbox_education_toast_title">Rotate your device for a full-screen view</string>
-
<!-- Description of the rotate screen into portrait action. [CHAR LIMIT=NONE] -->
<string name="letterbox_education_screen_rotation_portrait_text">Rotate your screen to portrait</string>
@@ -192,7 +189,4 @@
<!-- Button text for dismissing the letterbox education dialog. [CHAR LIMIT=20] -->
<string name="letterbox_education_got_it">Got it</string>
- <!-- Accessibility description of the letterbox education toast expand to dialog button. [CHAR LIMIT=NONE] -->
- <string name="letterbox_education_expand_button_description">Expand for more information.</string>
-
</resources>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index a477bd7f8295..7ab683513570 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1790,6 +1790,7 @@ public class BubbleStackView extends FrameLayout
/**
* Changes the expanded state of the stack.
+ * Don't call this directly, call mBubbleData#setExpanded.
*
* @param shouldExpand whether the bubble stack should appear expanded
*/
@@ -1836,7 +1837,7 @@ public class BubbleStackView extends FrameLayout
} else if (mManageEduView != null && mManageEduView.getVisibility() == VISIBLE) {
mManageEduView.hide();
} else {
- setExpanded(false);
+ mBubbleData.setExpanded(false);
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduToastLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduToastLayout.java
deleted file mode 100644
index e7f592dcb14d..000000000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterboxedu/LetterboxEduToastLayout.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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 com.android.wm.shell.compatui.letterboxedu;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.wm.shell.R;
-
-/**
- * Container for the Letterbox Education Toast.
- */
-// TODO(b/215316431): Add tests
-public class LetterboxEduToastLayout extends FrameLayout {
-
- public LetterboxEduToastLayout(Context context) {
- this(context, null);
- }
-
- public LetterboxEduToastLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public LetterboxEduToastLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public LetterboxEduToastLayout(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
-
- /**
- * Register a callback for the dismiss button.
- * @param callback The callback to register
- */
- void setExpandOnClickListener(Runnable callback) {
- findViewById(R.id.letterbox_education_toast_expand).setOnClickListener(
- view -> callback.run());
- }
-
- /**
- * Updates the layout with the given app info.
- * @param appName The name of the app
- * @param appIcon The icon of the app
- */
- void updateAppInfo(String appName, Drawable appIcon) {
- ImageView icon = findViewById(R.id.letterbox_education_icon);
- icon.setContentDescription(appName);
- icon.setImageDrawable(appIcon);
- }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
index 72ead0023366..32861b698daa 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipMenuController.java
@@ -103,7 +103,7 @@ public class TvPipMenuController implements PipMenuController, TvPipMenuView.Lis
};
context.registerReceiverForAllUsers(closeSystemDialogsBroadcastReceiver,
new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), null /* permission */,
- mainHandler);
+ mainHandler, Context.RECEIVER_EXPORTED);
pipMediaController.addActionListener(this::onMediaActionsChanged);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index 3cfa541c1c86..d022ec15f232 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -89,9 +89,17 @@ interface ISplitScreen {
/**
* Version of startTasks using legacy transition system.
*/
- oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
- int sideTaskId, in Bundle sideOptions, int sidePosition,
- float splitRatio, in RemoteAnimationAdapter adapter) = 11;
+ oneway void startTasksWithLegacyTransition(int mainTaskId, in Bundle mainOptions,
+ int sideTaskId, in Bundle sideOptions, int sidePosition,
+ float splitRatio, in RemoteAnimationAdapter adapter) = 11;
+
+ /**
+ * Start a pair of intent and task using legacy transition system.
+ */
+ oneway void startIntentAndTaskWithLegacyTransition(in PendingIntent pendingIntent,
+ in Intent fillInIntent, int taskId, boolean intentFirst, in Bundle mainOptions,
+ in Bundle sideOptions, int sidePosition, float splitRatio,
+ in RemoteAnimationAdapter adapter) = 12;
/**
* Blocking call that notifies and gets additional split-screen targets when entering
@@ -100,5 +108,7 @@ interface ISplitScreen {
* @param appTargets apps that will be re-parented to display area
*/
RemoteAnimationTarget[] onGoingToRecentsLegacy(boolean cancel,
- in RemoteAnimationTarget[] appTargets) = 12;
+ in RemoteAnimationTarget[] appTargets) = 13;
+
+
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 3e6dc8241f4f..990b53a601f3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -641,6 +641,18 @@ public class SplitScreenController implements DragAndDropPolicy.Starter,
}
@Override
+ public void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent,
+ Intent fillInIntent, int taskId, boolean intentFirst, Bundle mainOptions,
+ Bundle sideOptions, int sidePosition, float splitRatio,
+ RemoteAnimationAdapter adapter) {
+ executeRemoteCallWithTaskPermission(mController,
+ "startIntentAndTaskWithLegacyTransition", (controller) ->
+ controller.mStageCoordinator.startIntentAndTaskWithLegacyTransition(
+ pendingIntent, fillInIntent, taskId, intentFirst, mainOptions,
+ sideOptions, sidePosition, splitRatio, adapter));
+ }
+
+ @Override
public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions,
@SplitPosition int sidePosition, float splitRatio,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index a2c2f591cde0..219530b46da4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -57,8 +57,10 @@ import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
+import android.app.PendingIntent;
import android.app.WindowConfiguration;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
@@ -467,6 +469,116 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mTaskOrganizer.applyTransaction(wct);
}
+ /** Start an intent and a task ordered by {@code intentFirst}. */
+ void startIntentAndTaskWithLegacyTransition(PendingIntent pendingIntent, Intent fillInIntent,
+ int taskId, boolean intentFirst, @Nullable Bundle mainOptions,
+ @Nullable Bundle sideOptions, @SplitPosition int sidePosition, float splitRatio,
+ RemoteAnimationAdapter adapter) {
+ // TODO: try pulling the first chunk of this method into a method so that it can be shared
+ // with startTasksWithLegacyTransition. So far attempts to do so result in failure in split.
+
+ // Init divider first to make divider leash for remote animation target.
+ mSplitLayout.init();
+ // Set false to avoid record new bounds with old task still on top;
+ mShouldUpdateRecents = false;
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ final WindowContainerTransaction evictWct = new WindowContainerTransaction();
+ prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
+ prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
+ // Need to add another wrapper here in shell so that we can inject the divider bar
+ // and also manage the process elevation via setRunningRemote
+ IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
+ @Override
+ public void onAnimationStart(@WindowManager.TransitionOldType int transit,
+ RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
+ RemoteAnimationTarget[] nonApps,
+ final IRemoteAnimationFinishedCallback finishedCallback) {
+ RemoteAnimationTarget[] augmentedNonApps =
+ new RemoteAnimationTarget[nonApps.length + 1];
+ for (int i = 0; i < nonApps.length; ++i) {
+ augmentedNonApps[i] = nonApps[i];
+ }
+ augmentedNonApps[augmentedNonApps.length - 1] = getDividerBarLegacyTarget();
+
+ IRemoteAnimationFinishedCallback wrapCallback =
+ new IRemoteAnimationFinishedCallback.Stub() {
+ @Override
+ public void onAnimationFinished() throws RemoteException {
+ mShouldUpdateRecents = true;
+ mSyncQueue.queue(evictWct);
+ mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
+ finishedCallback.onAnimationFinished();
+ }
+ };
+ try {
+ try {
+ ActivityTaskManager.getService().setRunningRemoteTransitionDelegate(
+ adapter.getCallingApplication());
+ } catch (SecurityException e) {
+ Slog.e(TAG, "Unable to boost animation thread. This should only happen"
+ + " during unit tests");
+ }
+ adapter.getRunner().onAnimationStart(transit, apps, wallpapers,
+ augmentedNonApps, wrapCallback);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error starting remote animation", e);
+ }
+ }
+
+ @Override
+ public void onAnimationCancelled() {
+ mShouldUpdateRecents = true;
+ mSyncQueue.queue(evictWct);
+ mSyncQueue.runInSync(t -> setDividerVisibility(true, t));
+ try {
+ adapter.getRunner().onAnimationCancelled();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error starting remote animation", e);
+ }
+ }
+ };
+ RemoteAnimationAdapter wrappedAdapter = new RemoteAnimationAdapter(
+ wrapper, adapter.getDuration(), adapter.getStatusBarTransitionDelay());
+
+ if (mainOptions == null) {
+ mainOptions = ActivityOptions.makeRemoteAnimation(wrappedAdapter).toBundle();
+ } else {
+ ActivityOptions mainActivityOptions = ActivityOptions.fromBundle(mainOptions);
+ mainActivityOptions.update(ActivityOptions.makeRemoteAnimation(wrappedAdapter));
+ mainOptions = mainActivityOptions.toBundle();
+ }
+
+ sideOptions = sideOptions != null ? sideOptions : new Bundle();
+ setSideStagePosition(sidePosition, wct);
+
+ mSplitLayout.setDivideRatio(splitRatio);
+ if (mMainStage.isActive()) {
+ mMainStage.moveToTop(getMainStageBounds(), wct);
+ } else {
+ // Build a request WCT that will launch both apps such that task 0 is on the main stage
+ // while task 1 is on the side stage.
+ mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
+ }
+ mSideStage.moveToTop(getSideStageBounds(), wct);
+
+ // Make sure the launch options will put tasks in the corresponding split roots
+ addActivityOptions(mainOptions, mMainStage);
+ addActivityOptions(sideOptions, mSideStage);
+
+ // Add task launch requests
+ if (intentFirst) {
+ wct.sendPendingIntent(pendingIntent, fillInIntent, mainOptions);
+ wct.startTask(taskId, sideOptions);
+ } else {
+ wct.startTask(taskId, mainOptions);
+ wct.sendPendingIntent(pendingIntent, fillInIntent, sideOptions);
+ }
+
+ // Using legacy transitions, so we can't use blast sync since it conflicts.
+ mTaskOrganizer.applyTransaction(wct);
+ }
+
/**
* Collects all the current child tasks of a specific split and prepares transaction to evict
* them to display.
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index 574a9f4da627..556742e2ac5f 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -26,8 +26,16 @@
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6000s" />
<option name="hidden-api-checks" value="false" />
+ <option name="device-listeners"
+ value="com.android.server.wm.flicker.TraceFileReadyListener" />
</test>
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="(\w)+\.winscope" />
+ <option name="pull-pattern-keys" value="(\w)+\.mp4" />
+ <option name="collect-on-run-ended-only" value="false" />
+ <option name="clean-up" value="true" />
+ </metrics_collector>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="directory-keys" value="/sdcard/flicker" />
<option name="collect-on-run-ended-only" value="true" />
<option name="clean-up" value="true" />
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 6524182e9082..906123914731 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -93,7 +93,7 @@ class ExitPipWithSwipeDownTest(testSpec: FlickerTestParameter) : ExitPipTransiti
fun getParams(): List<FlickerTestParameter> {
return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 20)
+ repetitions = 5)
}
}
} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index 960c7ac4099a..b738c47ef6ff 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -75,7 +75,8 @@ public class BackAnimationControllerTest {
screenshotSurface,
hardwareBuffer,
new WindowConfiguration(),
- new RemoteCallback((bundle) -> {}));
+ new RemoteCallback((bundle) -> {}),
+ null);
try {
doReturn(navigationInfo).when(mActivityTaskManager).startBackNavigation();
} catch (RemoteException ex) {
diff --git a/media/Android.bp b/media/Android.bp
index fcdfd72c91d5..5aedcfbc22e9 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -108,6 +108,11 @@ aidl_interface {
vndk: {
enabled: true,
},
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.bluetooth",
+ ],
},
},
}
diff --git a/media/java/android/media/AudioDescriptor.java b/media/java/android/media/AudioDescriptor.java
index 11371b11e905..df648be4c157 100644
--- a/media/java/android/media/AudioDescriptor.java
+++ b/media/java/android/media/AudioDescriptor.java
@@ -18,16 +18,21 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Objects;
/**
* The AudioDescriptor contains the information to describe the audio playback/capture
* capabilities. The capabilities are described by a byte array, which is defined by a
* particular standard. This is used when the format is unrecognized to the platform.
*/
-public class AudioDescriptor {
+public class AudioDescriptor implements Parcelable {
/**
* The audio standard is not specified.
*/
@@ -49,7 +54,15 @@ public class AudioDescriptor {
private final byte[] mDescriptor;
private final int mEncapsulationType;
- AudioDescriptor(int standard, int encapsulationType, @NonNull byte[] descriptor) {
+ /**
+ * @hide
+ * Constructor from standard, encapsulation type and descriptor
+ * @param standard the standard of the audio descriptor
+ * @param encapsulationType the encapsulation type of the audio descriptor
+ * @param descriptor the audio descriptor
+ */
+ @SystemApi
+ public AudioDescriptor(int standard, int encapsulationType, @NonNull byte[] descriptor) {
mStandard = standard;
mEncapsulationType = encapsulationType;
mDescriptor = descriptor;
@@ -87,4 +100,66 @@ public class AudioDescriptor {
public @AudioProfile.EncapsulationType int getEncapsulationType() {
return mEncapsulationType;
}
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mStandard, mEncapsulationType, Arrays.hashCode(mDescriptor));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ AudioDescriptor that = (AudioDescriptor) o;
+ return ((mStandard == that.mStandard)
+ && (mEncapsulationType == that.mEncapsulationType)
+ && (Arrays.equals(mDescriptor, that.mDescriptor)));
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("{");
+ sb.append("standard=" + mStandard);
+ sb.append(", encapsulation type=" + mEncapsulationType);
+ if (mDescriptor != null && mDescriptor.length > 0) {
+ sb.append(", descriptor=").append(Arrays.toString(mDescriptor));
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mStandard);
+ dest.writeInt(mEncapsulationType);
+ dest.writeByteArray(mDescriptor);
+ }
+
+ private AudioDescriptor(@NonNull Parcel in) {
+ mStandard = in.readInt();
+ mEncapsulationType = in.readInt();
+ mDescriptor = in.createByteArray();
+ }
+
+ public static final @NonNull Parcelable.Creator<AudioDescriptor> CREATOR =
+ new Parcelable.Creator<AudioDescriptor>() {
+ /**
+ * Rebuilds an AudioDescriptor previously stored with writeToParcel().
+ * @param p Parcel object to read the AudioDescriptor from
+ * @return a new AudioDescriptor created from the data in the parcel
+ */
+ public AudioDescriptor createFromParcel(Parcel p) {
+ return new AudioDescriptor(p);
+ }
+
+ public AudioDescriptor[] newArray(int size) {
+ return new AudioDescriptor[size];
+ }
+ };
}
diff --git a/media/java/android/media/AudioDeviceAttributes.java b/media/java/android/media/AudioDeviceAttributes.java
index 1448c49105b2..af3c295b8d6c 100644
--- a/media/java/android/media/AudioDeviceAttributes.java
+++ b/media/java/android/media/AudioDeviceAttributes.java
@@ -18,12 +18,16 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
@@ -65,16 +69,27 @@ public final class AudioDeviceAttributes implements Parcelable {
* The unique address of the device. Some devices don't have addresses, only an empty string.
*/
private final @NonNull String mAddress;
-
+ /**
+ * The non-unique name of the device. Some devices don't have names, only an empty string.
+ * Should not be used as a unique identifier for a device.
+ */
+ private final @NonNull String mName;
/**
* Is input or output device
*/
private final @Role int mRole;
-
/**
* The internal audio device type
*/
private final int mNativeType;
+ /**
+ * List of AudioProfiles supported by the device
+ */
+ private final @NonNull List<AudioProfile> mAudioProfiles;
+ /**
+ * List of AudioDescriptors supported by the device
+ */
+ private final @NonNull List<AudioDescriptor> mAudioDescriptors;
/**
* @hide
@@ -88,7 +103,10 @@ public final class AudioDeviceAttributes implements Parcelable {
mRole = deviceInfo.isSink() ? ROLE_OUTPUT : ROLE_INPUT;
mType = deviceInfo.getType();
mAddress = deviceInfo.getAddress();
+ mName = String.valueOf(deviceInfo.getProductName());
mNativeType = deviceInfo.getInternalType();
+ mAudioProfiles = deviceInfo.getAudioProfiles();
+ mAudioDescriptors = deviceInfo.getAudioDescriptors();
}
/**
@@ -100,7 +118,24 @@ public final class AudioDeviceAttributes implements Parcelable {
*/
@SystemApi
public AudioDeviceAttributes(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
- @NonNull String address) {
+ @NonNull String address) {
+ this(role, type, address, "", new ArrayList<>(), new ArrayList<>());
+ }
+
+ /**
+ * @hide
+ * Constructor with specification of all attributes
+ * @param role indicates input or output role
+ * @param type the device type, as defined in {@link AudioDeviceInfo}
+ * @param address the address of the device, or an empty string for devices without one
+ * @param name the name of the device, or an empty string for devices without one
+ * @param profiles the list of AudioProfiles supported by the device
+ * @param descriptors the list of AudioDescriptors supported by the device
+ */
+ @SystemApi
+ public AudioDeviceAttributes(@Role int role, @AudioDeviceInfo.AudioDeviceType int type,
+ @NonNull String address, @NonNull String name, @NonNull List<AudioProfile> profiles,
+ @NonNull List<AudioDescriptor> descriptors) {
Objects.requireNonNull(address);
if (role != ROLE_OUTPUT && role != ROLE_INPUT) {
throw new IllegalArgumentException("Invalid role " + role);
@@ -118,19 +153,37 @@ public final class AudioDeviceAttributes implements Parcelable {
mRole = role;
mType = type;
mAddress = address;
+ mName = name;
+ mAudioProfiles = profiles;
+ mAudioDescriptors = descriptors;
}
/**
* @hide
- * Constructor from internal device type and address
- * @param type the internal device type, as defined in {@link AudioSystem}
+ * Constructor called from AudioSystem JNI when creating an AudioDeviceAttributes from a native
+ * AudioDeviceTypeAddr instance.
+ * @param nativeType the internal device type, as defined in {@link AudioSystem}
* @param address the address of the device, or an empty string for devices without one
*/
public AudioDeviceAttributes(int nativeType, @NonNull String address) {
+ this(nativeType, address, "");
+ }
+
+ /**
+ * @hide
+ * Constructor called from BtHelper to connect or disconnect a Bluetooth device.
+ * @param nativeType the internal device type, as defined in {@link AudioSystem}
+ * @param address the address of the device, or an empty string for devices without one
+ * @param name the name of the device, or an empty string for devices without one
+ */
+ public AudioDeviceAttributes(int nativeType, @NonNull String address, @NonNull String name) {
mRole = (nativeType & AudioSystem.DEVICE_BIT_IN) != 0 ? ROLE_INPUT : ROLE_OUTPUT;
mType = AudioDeviceInfo.convertInternalDeviceToDeviceType(nativeType);
mAddress = address;
+ mName = name;
mNativeType = nativeType;
+ mAudioProfiles = new ArrayList<>();
+ mAudioDescriptors = new ArrayList<>();
}
/**
@@ -165,6 +218,16 @@ public final class AudioDeviceAttributes implements Parcelable {
/**
* @hide
+ * Returns the name of the audio device, or an empty string for devices without one
+ * @return the device name
+ */
+ @SystemApi
+ public @NonNull String getName() {
+ return mName;
+ }
+
+ /**
+ * @hide
* Returns the internal device type of a device
* @return the internal device type
*/
@@ -172,9 +235,29 @@ public final class AudioDeviceAttributes implements Parcelable {
return mNativeType;
}
+ /**
+ * @hide
+ * Returns the list of AudioProfiles supported by the device
+ * @return the list of AudioProfiles
+ */
+ @SystemApi
+ public @NonNull List<AudioProfile> getAudioProfiles() {
+ return mAudioProfiles;
+ }
+
+ /**
+ * @hide
+ * Returns the list of AudioDescriptors supported by the device
+ * @return the list of AudioDescriptors
+ */
+ @SystemApi
+ public @NonNull List<AudioDescriptor> getAudioDescriptors() {
+ return mAudioDescriptors;
+ }
+
@Override
public int hashCode() {
- return Objects.hash(mRole, mType, mAddress);
+ return Objects.hash(mRole, mType, mAddress, mName, mAudioProfiles, mAudioDescriptors);
}
@Override
@@ -185,6 +268,25 @@ public final class AudioDeviceAttributes implements Parcelable {
AudioDeviceAttributes that = (AudioDeviceAttributes) o;
return ((mRole == that.mRole)
&& (mType == that.mType)
+ && mAddress.equals(that.mAddress)
+ && mName.equals(that.mName)
+ && mAudioProfiles.equals(that.mAudioProfiles)
+ && mAudioDescriptors.equals(that.mAudioDescriptors));
+ }
+
+ /**
+ * Returns true if the role, type and address are equal. Called to compare with an
+ * AudioDeviceAttributes that was created from a native AudioDeviceTypeAddr instance.
+ * @param o object to compare with
+ * @return whether role, type and address are equal
+ */
+ public boolean equalTypeAddress(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ AudioDeviceAttributes that = (AudioDeviceAttributes) o;
+ return ((mRole == that.mRole)
+ && (mType == that.mType)
&& mAddress.equals(that.mAddress));
}
@@ -199,7 +301,10 @@ public final class AudioDeviceAttributes implements Parcelable {
+ " role:" + roleToString(mRole)
+ " type:" + (mRole == ROLE_OUTPUT ? AudioSystem.getOutputDeviceName(mNativeType)
: AudioSystem.getInputDeviceName(mNativeType))
- + " addr:" + mAddress);
+ + " addr:" + mAddress
+ + " name:" + mName
+ + " profiles:" + mAudioProfiles.toString()
+ + " descriptors:" + mAudioDescriptors.toString());
}
@Override
@@ -212,14 +317,26 @@ public final class AudioDeviceAttributes implements Parcelable {
dest.writeInt(mRole);
dest.writeInt(mType);
dest.writeString(mAddress);
+ dest.writeString(mName);
dest.writeInt(mNativeType);
+ dest.writeParcelableArray(
+ mAudioProfiles.toArray(new AudioProfile[mAudioProfiles.size()]), flags);
+ dest.writeParcelableArray(
+ mAudioDescriptors.toArray(new AudioDescriptor[mAudioDescriptors.size()]), flags);
}
private AudioDeviceAttributes(@NonNull Parcel in) {
mRole = in.readInt();
mType = in.readInt();
mAddress = in.readString();
+ mName = in.readString();
mNativeType = in.readInt();
+ AudioProfile[] audioProfilesArray =
+ in.readParcelableArray(AudioProfile.class.getClassLoader(), AudioProfile.class);
+ mAudioProfiles = new ArrayList<AudioProfile>(Arrays.asList(audioProfilesArray));
+ AudioDescriptor[] audioDescriptorsArray = in.readParcelableArray(
+ AudioDescriptor.class.getClassLoader(), AudioDescriptor.class);
+ mAudioDescriptors = new ArrayList<AudioDescriptor>(Arrays.asList(audioDescriptorsArray));
}
public static final @NonNull Parcelable.Creator<AudioDeviceAttributes> CREATOR =
diff --git a/media/java/android/media/AudioDeviceInfo.java b/media/java/android/media/AudioDeviceInfo.java
index dd17dc649bc7..3d08959901b1 100644
--- a/media/java/android/media/AudioDeviceInfo.java
+++ b/media/java/android/media/AudioDeviceInfo.java
@@ -421,7 +421,7 @@ public final class AudioDeviceInfo {
*/
public CharSequence getProductName() {
String portName = mPort.name();
- return portName.length() != 0 ? portName : android.os.Build.MODEL;
+ return (portName != null && portName.length() != 0) ? portName : android.os.Build.MODEL;
}
/**
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 15a398de9021..cdc31631637e 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -5874,7 +5874,7 @@ public class AudioManager {
return false;
}
- /**
+ /**
* Indicate wired accessory connection state change.
* @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
* @param state new connection state: 1 connected, 0 disconnected
@@ -5883,10 +5883,29 @@ public class AudioManager {
*/
@UnsupportedAppUsage
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
- public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
+ public void setWiredDeviceConnectionState(int device, int state, String address,
+ String name) {
+ final IAudioService service = getService();
+ int role = isOutputDevice(device)
+ ? AudioDeviceAttributes.ROLE_OUTPUT : AudioDeviceAttributes.ROLE_INPUT;
+ AudioDeviceAttributes attributes = new AudioDeviceAttributes(
+ role, AudioDeviceInfo.convertInternalDeviceToDeviceType(device), address,
+ name, new ArrayList<>()/*mAudioProfiles*/, new ArrayList<>()/*mAudioDescriptors*/);
+ setWiredDeviceConnectionState(attributes, state);
+ }
+
+ /**
+ * Indicate wired accessory connection state change and attributes.
+ * @param state new connection state: 1 connected, 0 disconnected
+ * @param attributes attributes of the connected device
+ * {@hide}
+ */
+ @UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
+ public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes, int state) {
final IAudioService service = getService();
try {
- service.setWiredDeviceConnectionState(type, state, address, name,
+ service.setWiredDeviceConnectionState(attributes, state,
mApplicationContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -5919,13 +5938,14 @@ public class AudioManager {
* @param newDevice Bluetooth device connected or null if there is no new devices
* @param previousDevice Bluetooth device disconnected or null if there is no disconnected
* devices
- * @param info contain all info related to the device. {@link BtProfileConnectionInfo}
+ * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo}
* {@hide}
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.BLUETOOTH_STACK)
public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice,
- @Nullable BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) {
+ @Nullable BluetoothDevice previousDevice,
+ @NonNull BluetoothProfileConnectionInfo info) {
final IAudioService service = getService();
try {
service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info);
diff --git a/media/java/android/media/AudioProfile.java b/media/java/android/media/AudioProfile.java
index ae8d0a5ad4ab..5c5f837dd07a 100644
--- a/media/java/android/media/AudioProfile.java
+++ b/media/java/android/media/AudioProfile.java
@@ -18,10 +18,14 @@ package android.media;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.Objects;
import java.util.stream.Collectors;
/**
@@ -33,7 +37,7 @@ import java.util.stream.Collectors;
* be reported in different audio profiles. The application can choose any of the encapsulation
* types.
*/
-public class AudioProfile {
+public class AudioProfile implements Parcelable {
/**
* No encapsulation type is specified.
*/
@@ -57,9 +61,19 @@ public class AudioProfile {
private final int[] mChannelIndexMasks;
private final int mEncapsulationType;
- AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks,
- @NonNull int[] channelIndexMasks,
- int encapsulationType) {
+ /**
+ * @hide
+ * Constructor from format, sampling rates, channel masks, channel index masks and
+ * encapsulation type.
+ * @param format the audio format
+ * @param samplingRates the supported sampling rates
+ * @param channelMasks the supported channel masks
+ * @param channelIndexMasks the supported channel index masks
+ * @param encapsulationType the encapsulation type of the encoding format
+ */
+ @SystemApi
+ public AudioProfile(int format, @NonNull int[] samplingRates, @NonNull int[] channelMasks,
+ @NonNull int[] channelIndexMasks, int encapsulationType) {
mFormat = format;
mSamplingRates = samplingRates;
mChannelMasks = channelMasks;
@@ -114,6 +128,26 @@ public class AudioProfile {
}
@Override
+ public int hashCode() {
+ return Objects.hash(mFormat, Arrays.hashCode(mSamplingRates),
+ Arrays.hashCode(mChannelMasks), Arrays.hashCode(mChannelIndexMasks),
+ mEncapsulationType);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ AudioProfile that = (AudioProfile) o;
+ return ((mFormat == that.mFormat)
+ && (hasIdenticalElements(mSamplingRates, that.mSamplingRates))
+ && (hasIdenticalElements(mChannelMasks, that.mChannelMasks))
+ && (hasIdenticalElements(mChannelIndexMasks, that.mChannelIndexMasks))
+ && (mEncapsulationType == that.mEncapsulationType));
+ }
+
+ @Override
public String toString() {
StringBuilder sb = new StringBuilder("{");
sb.append(AudioFormat.toLogFriendlyEncoding(mFormat));
@@ -126,6 +160,7 @@ public class AudioProfile {
if (mChannelIndexMasks != null && mChannelIndexMasks.length > 0) {
sb.append(", channel index masks=").append(Arrays.toString(mChannelIndexMasks));
}
+ sb.append(", encapsulation type=" + mEncapsulationType);
sb.append("}");
return sb.toString();
}
@@ -137,4 +172,50 @@ public class AudioProfile {
return Arrays.stream(ints).mapToObj(anInt -> String.format("0x%02X", anInt))
.collect(Collectors.joining(", "));
}
+
+ private static boolean hasIdenticalElements(int[] array1, int[] array2) {
+ int[] sortedArray1 = Arrays.copyOf(array1, array1.length);
+ Arrays.sort(sortedArray1);
+ int[] sortedArray2 = Arrays.copyOf(array2, array2.length);
+ Arrays.sort(sortedArray2);
+ return Arrays.equals(sortedArray1, sortedArray2);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mFormat);
+ dest.writeIntArray(mSamplingRates);
+ dest.writeIntArray(mChannelMasks);
+ dest.writeIntArray(mChannelIndexMasks);
+ dest.writeInt(mEncapsulationType);
+ }
+
+ private AudioProfile(@NonNull Parcel in) {
+ mFormat = in.readInt();
+ mSamplingRates = in.createIntArray();
+ mChannelMasks = in.createIntArray();
+ mChannelIndexMasks = in.createIntArray();
+ mEncapsulationType = in.readInt();
+ }
+
+ public static final @NonNull Parcelable.Creator<AudioProfile> CREATOR =
+ new Parcelable.Creator<AudioProfile>() {
+ /**
+ * Rebuilds an AudioProfile previously stored with writeToParcel().
+ * @param p Parcel object to read the AudioProfile from
+ * @return a new AudioProfile created from the data in the parcel
+ */
+ public AudioProfile createFromParcel(Parcel p) {
+ return new AudioProfile(p);
+ }
+
+ public AudioProfile[] newArray(int size) {
+ return new AudioProfile[size];
+ }
+ };
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 1b46a50d7886..536b4ad71285 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -26,10 +26,12 @@ import android.bluetooth.BluetoothLeAudioCodecConfig;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.media.audio.common.AidlConversion;
import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
import android.os.Build;
import android.os.IBinder;
+import android.os.Parcel;
import android.os.Vibrator;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -1555,9 +1557,24 @@ public class AudioSystem
* {@link #AUDIO_STATUS_ERROR} or {@link #AUDIO_STATUS_SERVER_DIED}
*/
@UnsupportedAppUsage
- public static native int setDeviceConnectionState(int device, int state,
- String device_address, String device_name,
- int codecFormat);
+ public static int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
+ int codecFormat) {
+ android.media.audio.common.AudioPort port =
+ AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(attributes);
+ Parcel parcel = Parcel.obtain();
+ port.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ try {
+ return setDeviceConnectionState(state, parcel, codecFormat);
+ } finally {
+ parcel.recycle();
+ }
+ }
+ /**
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static native int setDeviceConnectionState(int state, Parcel parcel, int codecFormat);
/** @hide */
@UnsupportedAppUsage
public static native int getDeviceConnectionState(int device, String device_address);
diff --git a/media/java/android/media/BtProfileConnectionInfo.aidl b/media/java/android/media/BluetoothProfileConnectionInfo.aidl
index 047f06be0964..0617084fd826 100644
--- a/media/java/android/media/BtProfileConnectionInfo.aidl
+++ b/media/java/android/media/BluetoothProfileConnectionInfo.aidl
@@ -16,5 +16,5 @@
package android.media;
-parcelable BtProfileConnectionInfo;
+parcelable BluetoothProfileConnectionInfo;
diff --git a/media/java/android/media/BtProfileConnectionInfo.java b/media/java/android/media/BluetoothProfileConnectionInfo.java
index 88b9777e911d..c14884657ddd 100644
--- a/media/java/android/media/BtProfileConnectionInfo.java
+++ b/media/java/android/media/BluetoothProfileConnectionInfo.java
@@ -26,15 +26,14 @@ import android.os.Parcelable;
* {@hide}
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public final class BtProfileConnectionInfo implements Parcelable {
-
+public final class BluetoothProfileConnectionInfo implements Parcelable {
private final int mProfile;
private final boolean mSupprNoisy;
private final int mVolume;
private final boolean mIsLeOutput;
- private BtProfileConnectionInfo(int profile, boolean suppressNoisyIntent, int volume,
- boolean isLeOutput) {
+ private BluetoothProfileConnectionInfo(int profile, boolean suppressNoisyIntent,
+ int volume, boolean isLeOutput) {
mProfile = profile;
mSupprNoisy = suppressNoisyIntent;
mVolume = volume;
@@ -45,21 +44,21 @@ public final class BtProfileConnectionInfo implements Parcelable {
* Constructor used by BtHelper when a profile is connected
* {@hide}
*/
- public BtProfileConnectionInfo(int profile) {
+ public BluetoothProfileConnectionInfo(int profile) {
this(profile, false, -1, false);
}
- public static final @NonNull Parcelable.Creator<BtProfileConnectionInfo> CREATOR =
- new Parcelable.Creator<BtProfileConnectionInfo>() {
+ public static final @NonNull Parcelable.Creator<BluetoothProfileConnectionInfo> CREATOR =
+ new Parcelable.Creator<BluetoothProfileConnectionInfo>() {
@Override
- public BtProfileConnectionInfo createFromParcel(Parcel source) {
- return new BtProfileConnectionInfo(source.readInt(), source.readBoolean(),
- source.readInt(), source.readBoolean());
+ public BluetoothProfileConnectionInfo createFromParcel(Parcel source) {
+ return new BluetoothProfileConnectionInfo(source.readInt(),
+ source.readBoolean(), source.readInt(), source.readBoolean());
}
@Override
- public BtProfileConnectionInfo[] newArray(int size) {
- return new BtProfileConnectionInfo[size];
+ public BluetoothProfileConnectionInfo[] newArray(int size) {
+ return new BluetoothProfileConnectionInfo[size];
}
};
@@ -84,10 +83,10 @@ public final class BtProfileConnectionInfo implements Parcelable {
*
* @param volume of device -1 to ignore value
*/
- public static @NonNull BtProfileConnectionInfo a2dpInfo(boolean suppressNoisyIntent,
- int volume) {
- return new BtProfileConnectionInfo(BluetoothProfile.A2DP, suppressNoisyIntent, volume,
- false);
+ public static @NonNull BluetoothProfileConnectionInfo createA2dpInfo(
+ boolean suppressNoisyIntent, int volume) {
+ return new BluetoothProfileConnectionInfo(BluetoothProfile.A2DP, suppressNoisyIntent,
+ volume, false);
}
/**
@@ -96,8 +95,8 @@ public final class BtProfileConnectionInfo implements Parcelable {
*
* @param volume of device -1 to ignore value
*/
- public static @NonNull BtProfileConnectionInfo a2dpSinkInfo(int volume) {
- return new BtProfileConnectionInfo(BluetoothProfile.A2DP_SINK, true, volume, false);
+ public static @NonNull BluetoothProfileConnectionInfo createA2dpSinkInfo(int volume) {
+ return new BluetoothProfileConnectionInfo(BluetoothProfile.A2DP_SINK, true, volume, false);
}
/**
@@ -106,9 +105,10 @@ public final class BtProfileConnectionInfo implements Parcelable {
* @param suppressNoisyIntent if true the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY}
* intent will not be sent.
*/
- public static @NonNull BtProfileConnectionInfo hearingAidInfo(boolean suppressNoisyIntent) {
- return new BtProfileConnectionInfo(BluetoothProfile.HEARING_AID, suppressNoisyIntent, -1,
- false);
+ public static @NonNull BluetoothProfileConnectionInfo createHearingAidInfo(
+ boolean suppressNoisyIntent) {
+ return new BluetoothProfileConnectionInfo(BluetoothProfile.HEARING_AID, suppressNoisyIntent,
+ -1, false);
}
/**
@@ -119,10 +119,10 @@ public final class BtProfileConnectionInfo implements Parcelable {
*
* @param isLeOutput if true mean the device is an output device, if false it's an input device
*/
- public static @NonNull BtProfileConnectionInfo leAudio(boolean suppressNoisyIntent,
- boolean isLeOutput) {
- return new BtProfileConnectionInfo(BluetoothProfile.LE_AUDIO, suppressNoisyIntent, -1,
- isLeOutput);
+ public static @NonNull BluetoothProfileConnectionInfo createLeAudioInfo(
+ boolean suppressNoisyIntent, boolean isLeOutput) {
+ return new BluetoothProfileConnectionInfo(BluetoothProfile.LE_AUDIO, suppressNoisyIntent,
+ -1, isLeOutput);
}
/**
@@ -136,7 +136,7 @@ public final class BtProfileConnectionInfo implements Parcelable {
* @return {@code true} if {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be
* sent
*/
- public boolean getSuppressNoisyIntent() {
+ public boolean isSuppressNoisyIntent() {
return mSupprNoisy;
}
@@ -153,7 +153,7 @@ public final class BtProfileConnectionInfo implements Parcelable {
* @return {@code true} is the LE device is an output device, {@code false} if it's an input
* device
*/
- public boolean getIsLeOutput() {
+ public boolean isLeOutput() {
return mIsLeOutput;
}
}
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 96199a988704..fec14def618c 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -25,7 +25,7 @@ import android.media.AudioFocusInfo;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
-import android.media.BtProfileConnectionInfo;
+import android.media.BluetoothProfileConnectionInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioModeDispatcher;
import android.media.IAudioRoutesObserver;
@@ -215,8 +215,7 @@ interface IAudioService {
IRingtonePlayer getRingtonePlayer();
int getUiSoundsStreamType();
- void setWiredDeviceConnectionState(int type, int state, String address, String name,
- String caller);
+ void setWiredDeviceConnectionState(in AudioDeviceAttributes aa, int state, String caller);
@UnsupportedAppUsage
AudioRoutesInfo startWatchingRoutes(in IAudioRoutesObserver observer);
@@ -276,7 +275,7 @@ interface IAudioService {
oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
void handleBluetoothActiveDeviceChanged(in BluetoothDevice newDevice,
- in BluetoothDevice previousDevice, in BtProfileConnectionInfo info);
+ in BluetoothDevice previousDevice, in BluetoothProfileConnectionInfo info);
oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
in IAudioPolicyCallback pcb);
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index e2e48d35a672..5f02a430f384 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -43,6 +43,7 @@ import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.StampedLock;
/**
* <p>The ImageReader class allows direct application access to image data
@@ -675,7 +676,8 @@ public class ImageReader implements AutoCloseable {
* If no handler specified and the calling thread has no looper.
*/
public void setOnImageAvailableListener(OnImageAvailableListener listener, Handler handler) {
- synchronized (mListenerLock) {
+ long writeStamp = mListenerLock.writeLock();
+ try {
if (listener != null) {
Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
if (looper == null) {
@@ -691,6 +693,8 @@ public class ImageReader implements AutoCloseable {
mListenerExecutor = null;
}
mListener = listener;
+ } finally {
+ mListenerLock.unlockWrite(writeStamp);
}
}
@@ -713,9 +717,12 @@ public class ImageReader implements AutoCloseable {
throw new IllegalArgumentException("executor must not be null");
}
- synchronized (mListenerLock) {
+ long writeStamp = mListenerLock.writeLock();
+ try {
mListenerExecutor = executor;
mListener = listener;
+ } finally {
+ mListenerLock.unlockWrite(writeStamp);
}
}
@@ -731,6 +738,8 @@ public class ImageReader implements AutoCloseable {
/**
* Callback that is called when a new image is available from ImageReader.
*
+ * This callback must not modify or close the passed {@code reader}.
+ *
* @param reader the ImageReader the callback is associated with.
* @see ImageReader
* @see Image
@@ -889,28 +898,41 @@ public class ImageReader implements AutoCloseable {
return;
}
+ synchronized (ir.mCloseLock) {
+ if (!ir.mIsReaderValid) {
+ // It's dangerous to fire onImageAvailable() callback when the ImageReader
+ // is being closed, as application could acquire next image in the
+ // onImageAvailable() callback.
+ return;
+ }
+ }
+
final Executor executor;
- final OnImageAvailableListener listener;
- synchronized (ir.mListenerLock) {
+ final long readStamp = ir.mListenerLock.readLock();
+ try {
executor = ir.mListenerExecutor;
- listener = ir.mListener;
- }
- final boolean isReaderValid;
- synchronized (ir.mCloseLock) {
- isReaderValid = ir.mIsReaderValid;
+ if (executor == null) {
+ return;
+ }
+ } finally {
+ ir.mListenerLock.unlockRead(readStamp);
}
- // It's dangerous to fire onImageAvailable() callback when the ImageReader
- // is being closed, as application could acquire next image in the
- // onImageAvailable() callback.
- if (executor != null && listener != null && isReaderValid) {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- listener.onImageAvailable(ir);
+ executor.execute(() -> {
+ // Acquire readlock to ensure that the ImageReader does not change its
+ // state while a listener is actively processing.
+ final long rStamp = ir.mListenerLock.readLock();
+ try {
+ // Fire onImageAvailable of the latest non-null listener
+ // This ensures that if the listener changes while messages are in queue, the
+ // in-flight messages will call onImageAvailable of the new listener instead
+ if (ir.mListener != null) {
+ ir.mListener.onImageAvailable(ir);
}
- });
- }
+ } finally {
+ ir.mListenerLock.unlockRead(rStamp);
+ }
+ });
}
/**
@@ -1070,7 +1092,7 @@ public class ImageReader implements AutoCloseable {
private Surface mSurface;
private int mEstimatedNativeAllocBytes;
- private final Object mListenerLock = new Object();
+ private final StampedLock mListenerLock = new StampedLock();
private final Object mCloseLock = new Object();
private boolean mIsReaderValid = false;
private OnImageAvailableListener mListener;
diff --git a/media/java/android/media/audio/common/AidlConversion.java b/media/java/android/media/audio/common/AidlConversion.java
index 1053fb717fda..f17189dedcba 100644
--- a/media/java/android/media/audio/common/AidlConversion.java
+++ b/media/java/android/media/audio/common/AidlConversion.java
@@ -17,12 +17,17 @@
package android.media.audio.common;
import android.annotation.NonNull;
+import android.media.AudioDescriptor;
+import android.media.AudioDeviceAttributes;
import android.media.AudioFormat;
+import android.media.AudioSystem;
import android.media.MediaFormat;
import android.os.Parcel;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.stream.Collectors;
+
/**
* This class provides utility functions for converting between
* the AIDL types defined in 'android.media.audio.common' and:
@@ -525,6 +530,351 @@ public class AidlConversion {
}
}
+ /**
+ * Convert from SDK AudioDeviceAttributes to AIDL AudioPort.
+ */
+ public static AudioPort api2aidl_AudioDeviceAttributes_AudioPort(
+ @NonNull AudioDeviceAttributes attributes) {
+ AudioPort port = new AudioPort();
+ port.name = attributes.getName();
+ // TO DO: b/211611504 Convert attributes.getAudioProfiles() to AIDL as well.
+ port.profiles = new AudioProfile[]{};
+ port.extraAudioDescriptors = attributes.getAudioDescriptors().stream()
+ .map(descriptor -> api2aidl_AudioDescriptor_ExtraAudioDescriptor(descriptor))
+ .collect(Collectors.toList()).toArray(ExtraAudioDescriptor[]::new);
+ port.flags = new AudioIoFlags();
+ port.gains = new AudioGain[]{};
+ AudioPortDeviceExt deviceExt = new AudioPortDeviceExt();
+ deviceExt.device = new AudioDevice();
+ deviceExt.encodedFormats = new AudioFormatDescription[]{};
+ deviceExt.device.type =
+ api2aidl_NativeType_AudioDeviceDescription(attributes.getInternalType());
+ deviceExt.device.address = AudioDeviceAddress.id(attributes.getAddress());
+ port.ext = AudioPortExt.device(deviceExt);
+ return port;
+ }
+
+ /**
+ * Convert from SDK AudioDescriptor to AIDL ExtraAudioDescriptor.
+ */
+ public static ExtraAudioDescriptor api2aidl_AudioDescriptor_ExtraAudioDescriptor(
+ @NonNull AudioDescriptor descriptor) {
+ ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
+ extraDescriptor.standard =
+ api2aidl_AudioDescriptorStandard_AudioStandard(descriptor.getStandard());
+ extraDescriptor.audioDescriptor = descriptor.getDescriptor();
+ extraDescriptor.encapsulationType =
+ api2aidl_AudioProfileEncapsulationType_AudioEncapsulationType(
+ descriptor.getEncapsulationType());
+ return extraDescriptor;
+ }
+
+ /**
+ * Convert from SDK AudioDescriptor to AIDL ExtraAudioDescriptor.
+ */
+ public static @NonNull AudioDescriptor aidl2api_ExtraAudioDescriptor_AudioDescriptor(
+ @NonNull ExtraAudioDescriptor extraDescriptor) {
+ AudioDescriptor descriptor = new AudioDescriptor(
+ aidl2api_AudioStandard_AudioDescriptorStandard(extraDescriptor.standard),
+ aidl2api_AudioEncapsulationType_AudioProfileEncapsulationType(
+ extraDescriptor.encapsulationType),
+ extraDescriptor.audioDescriptor);
+ return descriptor;
+ }
+
+ /**
+ * Convert from SDK AudioDescriptor#mStandard to AIDL AudioStandard
+ */
+ @AudioStandard
+ public static int api2aidl_AudioDescriptorStandard_AudioStandard(
+ @AudioDescriptor.AudioDescriptorStandard int standard) {
+ switch (standard) {
+ case AudioDescriptor.STANDARD_EDID:
+ return AudioStandard.EDID;
+ case AudioDescriptor.STANDARD_NONE:
+ default:
+ return AudioStandard.NONE;
+ }
+ }
+
+ /**
+ * Convert from AIDL AudioStandard to SDK AudioDescriptor#mStandard
+ */
+ @AudioDescriptor.AudioDescriptorStandard
+ public static int aidl2api_AudioStandard_AudioDescriptorStandard(@AudioStandard int standard) {
+ switch (standard) {
+ case AudioStandard.EDID:
+ return AudioDescriptor.STANDARD_EDID;
+ case AudioStandard.NONE:
+ default:
+ return AudioDescriptor.STANDARD_NONE;
+ }
+ }
+
+ /**
+ * Convert from SDK AudioProfile.EncapsulationType to AIDL AudioEncapsulationType
+ */
+ @AudioEncapsulationType
+ public static int api2aidl_AudioProfileEncapsulationType_AudioEncapsulationType(
+ @android.media.AudioProfile.EncapsulationType int type) {
+ switch (type) {
+ case android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937:
+ return AudioEncapsulationType.IEC61937;
+ case android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE:
+ default:
+ return AudioEncapsulationType.NONE;
+ }
+ }
+
+ /**
+ * Convert from AIDL AudioEncapsulationType to SDK AudioProfile.EncapsulationType
+ */
+ @android.media.AudioProfile.EncapsulationType
+ public static int aidl2api_AudioEncapsulationType_AudioProfileEncapsulationType(
+ @AudioEncapsulationType int type) {
+ switch (type) {
+ case AudioEncapsulationType.IEC61937:
+ return android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937;
+ case AudioEncapsulationType.NONE:
+ default:
+ return android.media.AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE;
+ }
+ }
+
+ /**
+ * Convert from SDK native type to AIDL AudioDeviceDescription
+ */
+ public static AudioDeviceDescription api2aidl_NativeType_AudioDeviceDescription(
+ int nativeType) {
+ AudioDeviceDescription aidl = new AudioDeviceDescription();
+ aidl.connection = "";
+ switch (nativeType) {
+ case AudioSystem.DEVICE_OUT_EARPIECE:
+ aidl.type = AudioDeviceType.OUT_SPEAKER_EARPIECE;
+ break;
+ case AudioSystem.DEVICE_OUT_SPEAKER:
+ aidl.type = AudioDeviceType.OUT_SPEAKER;
+ break;
+ case AudioSystem.DEVICE_OUT_WIRED_HEADPHONE:
+ aidl.type = AudioDeviceType.OUT_HEADPHONE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+ break;
+ case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO:
+ aidl.type = AudioDeviceType.OUT_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+ break;
+ case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
+ aidl.type = AudioDeviceType.OUT_CARKIT;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+ break;
+ case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES:
+ aidl.type = AudioDeviceType.OUT_HEADPHONE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+ break;
+ case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
+ aidl.type = AudioDeviceType.OUT_SPEAKER;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+ break;
+ case AudioSystem.DEVICE_OUT_TELEPHONY_TX:
+ aidl.type = AudioDeviceType.OUT_TELEPHONY_TX;
+ break;
+ case AudioSystem.DEVICE_OUT_AUX_LINE:
+ aidl.type = AudioDeviceType.OUT_LINE_AUX;
+ break;
+ case AudioSystem.DEVICE_OUT_SPEAKER_SAFE:
+ aidl.type = AudioDeviceType.OUT_SPEAKER_SAFE;
+ break;
+ case AudioSystem.DEVICE_OUT_HEARING_AID:
+ aidl.type = AudioDeviceType.OUT_HEARING_AID;
+ aidl.connection = AudioDeviceDescription.CONNECTION_WIRELESS;
+ break;
+ case AudioSystem.DEVICE_OUT_ECHO_CANCELLER:
+ aidl.type = AudioDeviceType.OUT_ECHO_CANCELLER;
+ break;
+ case AudioSystem.DEVICE_OUT_BLE_SPEAKER:
+ aidl.type = AudioDeviceType.OUT_SPEAKER;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+ break;
+ case AudioSystem.DEVICE_IN_BUILTIN_MIC:
+ aidl.type = AudioDeviceType.IN_MICROPHONE;
+ break;
+ case AudioSystem.DEVICE_IN_BACK_MIC:
+ aidl.type = AudioDeviceType.IN_MICROPHONE_BACK;
+ break;
+ case AudioSystem.DEVICE_IN_TELEPHONY_RX:
+ aidl.type = AudioDeviceType.IN_TELEPHONY_RX;
+ break;
+ case AudioSystem.DEVICE_IN_TV_TUNER:
+ aidl.type = AudioDeviceType.IN_TV_TUNER;
+ break;
+ case AudioSystem.DEVICE_IN_LOOPBACK:
+ aidl.type = AudioDeviceType.IN_LOOPBACK;
+ break;
+ case AudioSystem.DEVICE_IN_BLUETOOTH_BLE:
+ aidl.type = AudioDeviceType.IN_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+ break;
+ case AudioSystem.DEVICE_IN_ECHO_REFERENCE:
+ aidl.type = AudioDeviceType.IN_ECHO_REFERENCE;
+ break;
+ case AudioSystem.DEVICE_IN_WIRED_HEADSET:
+ aidl.type = AudioDeviceType.IN_HEADSET;
+ aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+ break;
+ case AudioSystem.DEVICE_OUT_WIRED_HEADSET:
+ aidl.type = AudioDeviceType.OUT_HEADSET;
+ aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+ break;
+ case AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET:
+ aidl.type = AudioDeviceType.IN_HEADSET;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+ break;
+ case AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET:
+ aidl.type = AudioDeviceType.OUT_HEADSET;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_SCO;
+ break;
+ case AudioSystem.DEVICE_IN_HDMI:
+ aidl.type = AudioDeviceType.IN_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_HDMI;
+ break;
+ case AudioSystem.DEVICE_OUT_HDMI:
+ aidl.type = AudioDeviceType.OUT_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_HDMI;
+ break;
+ case AudioSystem.DEVICE_IN_REMOTE_SUBMIX:
+ aidl.type = AudioDeviceType.IN_SUBMIX;
+ break;
+ case AudioSystem.DEVICE_OUT_REMOTE_SUBMIX:
+ aidl.type = AudioDeviceType.OUT_SUBMIX;
+ break;
+ case AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET:
+ aidl.type = AudioDeviceType.IN_DOCK;
+ aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+ break;
+ case AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET:
+ aidl.type = AudioDeviceType.OUT_DOCK;
+ aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+ break;
+ case AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET:
+ aidl.type = AudioDeviceType.IN_DOCK;
+ aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+ break;
+ case AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET:
+ aidl.type = AudioDeviceType.OUT_DOCK;
+ aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+ break;
+ case AudioSystem.DEVICE_IN_USB_ACCESSORY:
+ aidl.type = AudioDeviceType.IN_ACCESSORY;
+ aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+ break;
+ case AudioSystem.DEVICE_OUT_USB_ACCESSORY:
+ aidl.type = AudioDeviceType.OUT_ACCESSORY;
+ aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+ break;
+ case AudioSystem.DEVICE_IN_USB_DEVICE:
+ aidl.type = AudioDeviceType.IN_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+ break;
+ case AudioSystem.DEVICE_OUT_USB_DEVICE:
+ aidl.type = AudioDeviceType.OUT_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+ break;
+ case AudioSystem.DEVICE_IN_FM_TUNER:
+ aidl.type = AudioDeviceType.IN_FM_TUNER;
+ break;
+ case AudioSystem.DEVICE_OUT_FM:
+ aidl.type = AudioDeviceType.OUT_FM;
+ break;
+ case AudioSystem.DEVICE_IN_LINE:
+ aidl.type = AudioDeviceType.IN_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+ break;
+ case AudioSystem.DEVICE_OUT_LINE:
+ aidl.type = AudioDeviceType.OUT_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_ANALOG;
+ break;
+ case AudioSystem.DEVICE_IN_SPDIF:
+ aidl.type = AudioDeviceType.IN_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_SPDIF;
+ break;
+ case AudioSystem.DEVICE_OUT_SPDIF:
+ aidl.type = AudioDeviceType.OUT_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_SPDIF;
+ break;
+ case AudioSystem.DEVICE_IN_BLUETOOTH_A2DP:
+ aidl.type = AudioDeviceType.IN_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+ break;
+ case AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP:
+ aidl.type = AudioDeviceType.OUT_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_A2DP;
+ break;
+ case AudioSystem.DEVICE_IN_IP:
+ aidl.type = AudioDeviceType.IN_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_IP_V4;
+ break;
+ case AudioSystem.DEVICE_OUT_IP:
+ aidl.type = AudioDeviceType.OUT_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_IP_V4;
+ break;
+ case AudioSystem.DEVICE_IN_BUS:
+ aidl.type = AudioDeviceType.IN_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BUS;
+ break;
+ case AudioSystem.DEVICE_OUT_BUS:
+ aidl.type = AudioDeviceType.OUT_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BUS;
+ break;
+ case AudioSystem.DEVICE_IN_PROXY:
+ aidl.type = AudioDeviceType.IN_AFE_PROXY;
+ break;
+ case AudioSystem.DEVICE_OUT_PROXY:
+ aidl.type = AudioDeviceType.OUT_AFE_PROXY;
+ break;
+ case AudioSystem.DEVICE_IN_USB_HEADSET:
+ aidl.type = AudioDeviceType.IN_HEADSET;
+ aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+ break;
+ case AudioSystem.DEVICE_OUT_USB_HEADSET:
+ aidl.type = AudioDeviceType.OUT_HEADSET;
+ aidl.connection = AudioDeviceDescription.CONNECTION_USB;
+ break;
+ case AudioSystem.DEVICE_IN_HDMI_ARC:
+ aidl.type = AudioDeviceType.IN_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_ARC;
+ break;
+ case AudioSystem.DEVICE_OUT_HDMI_ARC:
+ aidl.type = AudioDeviceType.OUT_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_ARC;
+ break;
+ case AudioSystem.DEVICE_IN_HDMI_EARC:
+ aidl.type = AudioDeviceType.IN_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_EARC;
+ break;
+ case AudioSystem.DEVICE_OUT_HDMI_EARC:
+ aidl.type = AudioDeviceType.OUT_DEVICE;
+ aidl.connection = AudioDeviceDescription.CONNECTION_HDMI_EARC;
+ break;
+ case AudioSystem.DEVICE_IN_BLE_HEADSET:
+ aidl.type = AudioDeviceType.IN_HEADSET;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+ break;
+ case AudioSystem.DEVICE_OUT_BLE_HEADSET:
+ aidl.type = AudioDeviceType.OUT_HEADSET;
+ aidl.connection = AudioDeviceDescription.CONNECTION_BT_LE;
+ break;
+ case AudioSystem.DEVICE_IN_DEFAULT:
+ aidl.type = AudioDeviceType.IN_DEFAULT;
+ break;
+ case AudioSystem.DEVICE_OUT_DEFAULT:
+ aidl.type = AudioDeviceType.OUT_DEFAULT;
+ break;
+ default:
+ aidl.type = AudioDeviceType.NONE;
+ }
+ return aidl;
+ }
+
private static native int aidl2legacy_AudioChannelLayout_Parcel_audio_channel_mask_t(
Parcel aidl, boolean isInput);
private static native Parcel legacy2aidl_audio_channel_mask_t_AudioChannelLayout_Parcel(
diff --git a/media/java/android/media/tv/tuner/DemuxCapabilities.java b/media/java/android/media/tv/tuner/DemuxCapabilities.java
index 0f5bf082d44f..14a9144c9cdc 100644
--- a/media/java/android/media/tv/tuner/DemuxCapabilities.java
+++ b/media/java/android/media/tv/tuner/DemuxCapabilities.java
@@ -36,13 +36,8 @@ import java.lang.annotation.RetentionPolicy;
public class DemuxCapabilities {
/** @hide */
- @IntDef(flag = true, value = {
- Filter.TYPE_TS,
- Filter.TYPE_MMTP,
- Filter.TYPE_IP,
- Filter.TYPE_TLV,
- Filter.TYPE_ALP
- })
+ @IntDef(value = {Filter.TYPE_TS, Filter.TYPE_MMTP, Filter.TYPE_IP, Filter.TYPE_TLV,
+ Filter.TYPE_ALP})
@Retention(RetentionPolicy.SOURCE)
public @interface FilterCapabilities {}
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 9f4423644877..14accaafe189 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -153,8 +153,8 @@ public class Filter implements AutoCloseable {
/** @hide */
- @IntDef(flag = true, prefix = "STATUS_", value = {STATUS_DATA_READY, STATUS_LOW_WATER,
- STATUS_HIGH_WATER, STATUS_OVERFLOW})
+ @IntDef(prefix = "STATUS_",
+ value = {STATUS_DATA_READY, STATUS_LOW_WATER, STATUS_HIGH_WATER, STATUS_OVERFLOW})
@Retention(RetentionPolicy.SOURCE)
public @interface Status {}
@@ -185,8 +185,7 @@ public class Filter implements AutoCloseable {
public static final int STATUS_OVERFLOW = DemuxFilterStatus.OVERFLOW;
/** @hide */
- @IntDef(flag = true,
- prefix = "SCRAMBLING_STATUS_",
+ @IntDef(prefix = "SCRAMBLING_STATUS_",
value = {SCRAMBLING_STATUS_UNKNOWN, SCRAMBLING_STATUS_NOT_SCRAMBLED,
SCRAMBLING_STATUS_SCRAMBLED})
@Retention(RetentionPolicy.SOURCE)
@@ -209,8 +208,7 @@ public class Filter implements AutoCloseable {
android.hardware.tv.tuner.ScramblingStatus.SCRAMBLED;
/** @hide */
- @IntDef(flag = true,
- prefix = "MONITOR_EVENT_",
+ @IntDef(prefix = "MONITOR_EVENT_",
value = {MONITOR_EVENT_SCRAMBLING_STATUS, MONITOR_EVENT_IP_CID_CHANGE})
@Retention(RetentionPolicy.SOURCE)
public @interface MonitorEventMask {}
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
index d34581da29cb..b16d9fb247b7 100644
--- a/media/java/android/media/tv/tuner/filter/RecordSettings.java
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -40,8 +40,7 @@ public class RecordSettings extends Settings {
*
* @hide
*/
- @IntDef(flag = true,
- value = {TS_INDEX_INVALID, TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
+ @IntDef(value = {TS_INDEX_INVALID, TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR,
TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED,
TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, TS_INDEX_DISCONTINUITY_INDICATOR,
TS_INDEX_RANDOM_ACCESS_INDICATOR, TS_INDEX_PRIORITY_INDICATOR,
@@ -165,7 +164,6 @@ public class RecordSettings extends Settings {
* @hide
*/
@IntDef(prefix = "SC_INDEX_",
- flag = true,
value = {SC_INDEX_I_FRAME, SC_INDEX_P_FRAME, SC_INDEX_B_FRAME,
SC_INDEX_SEQUENCE, SC_INDEX_I_SLICE, SC_INDEX_P_SLICE,
SC_INDEX_B_SLICE, SC_INDEX_SI_SLICE, SC_INDEX_SP_SLICE})
@@ -214,8 +212,7 @@ public class RecordSettings extends Settings {
*
* @hide
*/
- @IntDef(flag = true,
- value = {SC_HEVC_INDEX_SPS, SC_HEVC_INDEX_AUD, SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
+ @IntDef(value = {SC_HEVC_INDEX_SPS, SC_HEVC_INDEX_AUD, SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
SC_HEVC_INDEX_SLICE_BLA_W_RADL, SC_HEVC_INDEX_SLICE_BLA_N_LP,
SC_HEVC_INDEX_SLICE_IDR_W_RADL, SC_HEVC_INDEX_SLICE_IDR_N_LP,
SC_HEVC_INDEX_SLICE_TRAIL_CRA})
@@ -258,8 +255,7 @@ public class RecordSettings extends Settings {
/**
* @hide
*/
- @IntDef(flag = true,
- prefix = "SC_",
+ @IntDef(prefix = "SC_",
value = {
SC_INDEX_I_FRAME,
SC_INDEX_P_FRAME,
diff --git a/media/java/android/media/tv/tuner/filter/SharedFilter.java b/media/java/android/media/tv/tuner/filter/SharedFilter.java
index 740ab9c45c83..21964ee5a32a 100644
--- a/media/java/android/media/tv/tuner/filter/SharedFilter.java
+++ b/media/java/android/media/tv/tuner/filter/SharedFilter.java
@@ -38,7 +38,7 @@ import java.util.concurrent.Executor;
@SystemApi
public final class SharedFilter implements AutoCloseable {
/** @hide */
- @IntDef(flag = true, prefix = "STATUS_", value = {STATUS_INACCESSIBLE})
+ @IntDef(prefix = "STATUS_", value = {STATUS_INACCESSIBLE})
@Retention(RetentionPolicy.SOURCE)
public @interface Status {}
diff --git a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
index e0405ef57f2e..6c1134ae8fac 100644
--- a/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AnalogFrontendSettings.java
@@ -36,8 +36,7 @@ import java.lang.annotation.RetentionPolicy;
@SystemApi
public class AnalogFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "SIGNAL_TYPE_",
+ @IntDef(prefix = "SIGNAL_TYPE_",
value = {SIGNAL_TYPE_UNDEFINED, SIGNAL_TYPE_AUTO, SIGNAL_TYPE_PAL, SIGNAL_TYPE_PAL_M,
SIGNAL_TYPE_PAL_N, SIGNAL_TYPE_PAL_60, SIGNAL_TYPE_NTSC, SIGNAL_TYPE_NTSC_443,
SIGNAL_TYPE_SECAM})
@@ -82,8 +81,7 @@ public class AnalogFrontendSettings extends FrontendSettings {
public static final int SIGNAL_TYPE_SECAM = FrontendAnalogType.SECAM;
/** @hide */
- @IntDef(flag = true,
- prefix = "SIF_",
+ @IntDef(prefix = "SIF_",
value = {SIF_UNDEFINED, SIF_AUTO, SIF_BG, SIF_BG_A2, SIF_BG_NICAM, SIF_I, SIF_DK,
SIF_DK1_A2, SIF_DK2_A2, SIF_DK3_A2, SIF_DK_NICAM, SIF_L, SIF_M, SIF_M_BTSC, SIF_M_A2,
SIF_M_EIAJ, SIF_I_NICAM, SIF_L_NICAM, SIF_L_PRIME})
diff --git a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
index a7157e20c5e6..c99f911c4236 100644
--- a/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Atsc3FrontendSettings.java
@@ -39,8 +39,7 @@ import java.lang.annotation.RetentionPolicy;
public class Atsc3FrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "BANDWIDTH_",
+ @IntDef(prefix = "BANDWIDTH_",
value = {BANDWIDTH_UNDEFINED, BANDWIDTH_AUTO, BANDWIDTH_BANDWIDTH_6MHZ,
BANDWIDTH_BANDWIDTH_7MHZ, BANDWIDTH_BANDWIDTH_8MHZ})
@Retention(RetentionPolicy.SOURCE)
@@ -69,8 +68,7 @@ public class Atsc3FrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "MODULATION_",
+ @IntDef(prefix = "MODULATION_",
value = {MODULATION_UNDEFINED, MODULATION_AUTO,
MODULATION_MOD_QPSK, MODULATION_MOD_16QAM,
MODULATION_MOD_64QAM, MODULATION_MOD_256QAM,
@@ -113,8 +111,7 @@ public class Atsc3FrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "TIME_INTERLEAVE_MODE_",
+ @IntDef(prefix = "TIME_INTERLEAVE_MODE_",
value = {TIME_INTERLEAVE_MODE_UNDEFINED, TIME_INTERLEAVE_MODE_AUTO,
TIME_INTERLEAVE_MODE_CTI, TIME_INTERLEAVE_MODE_HTI})
@Retention(RetentionPolicy.SOURCE)
@@ -140,8 +137,7 @@ public class Atsc3FrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "CODERATE_",
+ @IntDef(prefix = "CODERATE_",
value = {CODERATE_UNDEFINED, CODERATE_AUTO, CODERATE_2_15, CODERATE_3_15, CODERATE_4_15,
CODERATE_5_15, CODERATE_6_15, CODERATE_7_15, CODERATE_8_15, CODERATE_9_15,
CODERATE_10_15, CODERATE_11_15, CODERATE_12_15, CODERATE_13_15})
@@ -207,8 +203,7 @@ public class Atsc3FrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "FEC_",
+ @IntDef(prefix = "FEC_",
value = {FEC_UNDEFINED, FEC_AUTO, FEC_BCH_LDPC_16K, FEC_BCH_LDPC_64K, FEC_CRC_LDPC_16K,
FEC_CRC_LDPC_64K, FEC_LDPC_16K, FEC_LDPC_64K})
@Retention(RetentionPolicy.SOURCE)
@@ -249,8 +244,7 @@ public class Atsc3FrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "DEMOD_OUTPUT_FORMAT_",
+ @IntDef(prefix = "DEMOD_OUTPUT_FORMAT_",
value = {DEMOD_OUTPUT_FORMAT_UNDEFINED, DEMOD_OUTPUT_FORMAT_ATSC3_LINKLAYER_PACKET,
DEMOD_OUTPUT_FORMAT_BASEBAND_PACKET})
@Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
index 3071ce861e0d..64c6ce629740 100644
--- a/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/AtscFrontendSettings.java
@@ -34,8 +34,7 @@ import java.lang.annotation.RetentionPolicy;
public class AtscFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "MODULATION_",
+ @IntDef(prefix = "MODULATION_",
value = {MODULATION_UNDEFINED, MODULATION_AUTO, MODULATION_MOD_8VSB,
MODULATION_MOD_16VSB})
@Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java
index 6b5d6ca9eb84..07c1fbffd91e 100644
--- a/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DtmbFrontendSettings.java
@@ -43,8 +43,7 @@ import java.lang.annotation.RetentionPolicy;
public final class DtmbFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "BANDWIDTH_",
+ @IntDef(prefix = "BANDWIDTH_",
value = {BANDWIDTH_UNDEFINED, BANDWIDTH_AUTO, BANDWIDTH_6MHZ, BANDWIDTH_8MHZ})
@Retention(RetentionPolicy.SOURCE)
public @interface Bandwidth {}
@@ -68,8 +67,7 @@ public final class DtmbFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "TIME_INTERLEAVE_MODE_",
+ @IntDef(prefix = "TIME_INTERLEAVE_MODE_",
value = {TIME_INTERLEAVE_MODE_UNDEFINED, TIME_INTERLEAVE_MODE_AUTO,
TIME_INTERLEAVE_MODE_TIMER_INT_240, TIME_INTERLEAVE_MODE_TIMER_INT_720})
@Retention(RetentionPolicy.SOURCE)
@@ -97,8 +95,7 @@ public final class DtmbFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "GUARD_INTERVAL_",
+ @IntDef(prefix = "GUARD_INTERVAL_",
value = {GUARD_INTERVAL_UNDEFINED, GUARD_INTERVAL_AUTO,
GUARD_INTERVAL_PN_420_VARIOUS, GUARD_INTERVAL_PN_595_CONST,
GUARD_INTERVAL_PN_945_VARIOUS, GUARD_INTERVAL_PN_420_CONST,
@@ -143,8 +140,7 @@ public final class DtmbFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "MODULATION_",
+ @IntDef(prefix = "MODULATION_",
value = {MODULATION_CONSTELLATION_UNDEFINED, MODULATION_CONSTELLATION_AUTO,
MODULATION_CONSTELLATION_4QAM, MODULATION_CONSTELLATION_4QAM_NR,
MODULATION_CONSTELLATION_16QAM, MODULATION_CONSTELLATION_32QAM,
@@ -187,8 +183,7 @@ public final class DtmbFrontendSettings extends FrontendSettings {
FrontendDtmbModulation.CONSTELLATION_64QAM;
/** @hide */
- @IntDef(flag = true,
- prefix = "CODERATE_",
+ @IntDef(prefix = "CODERATE_",
value = {CODERATE_UNDEFINED, CODERATE_AUTO, CODERATE_2_5, CODERATE_3_5, CODERATE_4_5})
@Retention(RetentionPolicy.SOURCE)
public @interface CodeRate {}
@@ -215,8 +210,7 @@ public final class DtmbFrontendSettings extends FrontendSettings {
public static final int CODERATE_4_5 = FrontendDtmbCodeRate.CODERATE_4_5;
/** @hide */
- @IntDef(flag = true,
- prefix = "TRANSMISSION_MODE_",
+ @IntDef(prefix = "TRANSMISSION_MODE_",
value = {TRANSMISSION_MODE_UNDEFINED, TRANSMISSION_MODE_AUTO,
TRANSMISSION_MODE_C1, TRANSMISSION_MODE_C3780})
@Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
index afe953de5389..45bfc09b8ae7 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbcFrontendSettings.java
@@ -40,8 +40,7 @@ import java.lang.annotation.RetentionPolicy;
public class DvbcFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "MODULATION_",
+ @IntDef(prefix = "MODULATION_",
value = {MODULATION_UNDEFINED, MODULATION_AUTO, MODULATION_MOD_16QAM,
MODULATION_MOD_32QAM, MODULATION_MOD_64QAM, MODULATION_MOD_128QAM,
MODULATION_MOD_256QAM})
@@ -98,8 +97,7 @@ public class DvbcFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "ANNEX_",
+ @IntDef(prefix = "ANNEX_",
value = {ANNEX_UNDEFINED, ANNEX_A, ANNEX_B, ANNEX_C})
@Retention(RetentionPolicy.SOURCE)
public @interface Annex {}
@@ -159,8 +157,7 @@ public class DvbcFrontendSettings extends FrontendSettings {
android.hardware.tv.tuner.FrontendSpectralInversion.INVERTED;
/** @hide */
- @IntDef(flag = true,
- prefix = "TIME_INTERLEAVE_MODE_",
+ @IntDef(prefix = "TIME_INTERLEAVE_MODE_",
value = {TIME_INTERLEAVE_MODE_UNDEFINED, TIME_INTERLEAVE_MODE_AUTO,
TIME_INTERLEAVE_MODE_128_1_0, TIME_INTERLEAVE_MODE_128_1_1,
TIME_INTERLEAVE_MODE_64_2, TIME_INTERLEAVE_MODE_32_4,
@@ -226,8 +223,7 @@ public class DvbcFrontendSettings extends FrontendSettings {
FrontendCableTimeInterleaveMode.INTERLEAVING_128_4;
/** @hide */
- @IntDef(flag = true,
- prefix = "BANDWIDTH_",
+ @IntDef(prefix = "BANDWIDTH_",
value = {BANDWIDTH_UNDEFINED, BANDWIDTH_5MHZ, BANDWIDTH_6MHZ, BANDWIDTH_7MHZ,
BANDWIDTH_8MHZ})
@Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
index e16f19285100..56dbb480880b 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbsFrontendSettings.java
@@ -42,8 +42,7 @@ import java.lang.annotation.RetentionPolicy;
@SystemApi
public class DvbsFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "SCAN_TYPE_",
+ @IntDef(prefix = "SCAN_TYPE_",
value = {SCAN_TYPE_UNDEFINED, SCAN_TYPE_DIRECT, SCAN_TYPE_DISEQC,
SCAN_TYPE_UNICABLE, SCAN_TYPE_JESS})
@Retention(RetentionPolicy.SOURCE)
@@ -75,8 +74,7 @@ public class DvbsFrontendSettings extends FrontendSettings {
public static final int SCAN_TYPE_JESS = FrontendDvbsScanType.JESS;
/** @hide */
- @IntDef(flag = true,
- prefix = "MODULATION_",
+ @IntDef(prefix = "MODULATION_",
value = {MODULATION_UNDEFINED, MODULATION_AUTO, MODULATION_MOD_QPSK,
MODULATION_MOD_8PSK, MODULATION_MOD_16QAM, MODULATION_MOD_16PSK,
MODULATION_MOD_32PSK, MODULATION_MOD_ACM, MODULATION_MOD_8APSK,
@@ -207,8 +205,7 @@ public class DvbsFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "STANDARD_",
+ @IntDef(prefix = "STANDARD_",
value = {STANDARD_AUTO, STANDARD_S, STANDARD_S2, STANDARD_S2X})
@Retention(RetentionPolicy.SOURCE)
public @interface Standard {}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index d86e9a8af5f6..06547e1fc0e7 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
@@ -42,8 +42,7 @@ import java.lang.annotation.RetentionPolicy;
public class DvbtFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "TRANSMISSION_MODE_",
+ @IntDef(prefix = "TRANSMISSION_MODE_",
value = {TRANSMISSION_MODE_UNDEFINED, TRANSMISSION_MODE_AUTO,
TRANSMISSION_MODE_2K, TRANSMISSION_MODE_8K, TRANSMISSION_MODE_4K,
TRANSMISSION_MODE_1K, TRANSMISSION_MODE_16K, TRANSMISSION_MODE_32K})
@@ -98,8 +97,7 @@ public class DvbtFrontendSettings extends FrontendSettings {
FrontendDvbtTransmissionMode.MODE_32K_E;
/** @hide */
- @IntDef(flag = true,
- prefix = "BANDWIDTH_",
+ @IntDef(prefix = "BANDWIDTH_",
value = {BANDWIDTH_UNDEFINED, BANDWIDTH_AUTO, BANDWIDTH_8MHZ, BANDWIDTH_7MHZ,
BANDWIDTH_6MHZ, BANDWIDTH_5MHZ, BANDWIDTH_1_7MHZ, BANDWIDTH_10MHZ})
@Retention(RetentionPolicy.SOURCE)
@@ -140,8 +138,7 @@ public class DvbtFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "CONSTELLATION_",
+ @IntDef(prefix = "CONSTELLATION_",
value = {CONSTELLATION_UNDEFINED, CONSTELLATION_AUTO, CONSTELLATION_QPSK,
CONSTELLATION_16QAM, CONSTELLATION_64QAM, CONSTELLATION_256QAM,
CONSTELLATION_QPSK_R, CONSTELLATION_16QAM_R, CONSTELLATION_64QAM_R,
@@ -192,8 +189,7 @@ public class DvbtFrontendSettings extends FrontendSettings {
FrontendDvbtConstellation.CONSTELLATION_256QAM_R;
/** @hide */
- @IntDef(flag = true,
- prefix = "HIERARCHY_",
+ @IntDef(prefix = "HIERARCHY_",
value = {HIERARCHY_UNDEFINED, HIERARCHY_AUTO, HIERARCHY_NON_NATIVE, HIERARCHY_1_NATIVE,
HIERARCHY_2_NATIVE, HIERARCHY_4_NATIVE, HIERARCHY_NON_INDEPTH, HIERARCHY_1_INDEPTH,
HIERARCHY_2_INDEPTH, HIERARCHY_4_INDEPTH})
@@ -243,8 +239,7 @@ public class DvbtFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "CODERATE_",
+ @IntDef(prefix = "CODERATE_",
value = {CODERATE_UNDEFINED, CODERATE_AUTO, CODERATE_1_2, CODERATE_2_3, CODERATE_3_4,
CODERATE_5_6, CODERATE_7_8, CODERATE_3_5, CODERATE_4_5, CODERATE_6_7, CODERATE_8_9})
@Retention(RetentionPolicy.SOURCE)
@@ -296,8 +291,7 @@ public class DvbtFrontendSettings extends FrontendSettings {
public static final int CODERATE_8_9 = FrontendDvbtCoderate.CODERATE_8_9;
/** @hide */
- @IntDef(flag = true,
- prefix = "GUARD_INTERVAL_",
+ @IntDef(prefix = "GUARD_INTERVAL_",
value = {GUARD_INTERVAL_UNDEFINED, GUARD_INTERVAL_AUTO,
GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_16,
GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_4,
@@ -346,8 +340,7 @@ public class DvbtFrontendSettings extends FrontendSettings {
public static final int GUARD_INTERVAL_19_256 = FrontendDvbtGuardInterval.INTERVAL_19_256;
/** @hide */
- @IntDef(flag = true,
- prefix = "STANDARD",
+ @IntDef(prefix = "STANDARD_",
value = {STANDARD_AUTO, STANDARD_T, STANDARD_T2}
)
@Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
index 38bffec3f77f..2f45a7072017 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendSettings.java
@@ -89,8 +89,7 @@ public abstract class FrontendSettings {
/** @hide */
- @LongDef(flag = true,
- prefix = "FEC_",
+ @LongDef(prefix = "FEC_",
value = {FEC_UNDEFINED, FEC_AUTO, FEC_1_2, FEC_1_3, FEC_1_4, FEC_1_5, FEC_2_3, FEC_2_5,
FEC_2_9, FEC_3_4, FEC_3_5, FEC_4_5, FEC_4_15, FEC_5_6, FEC_5_9, FEC_6_7, FEC_7_8,
FEC_7_9, FEC_7_15, FEC_8_9, FEC_8_15, FEC_9_10, FEC_9_20, FEC_11_15, FEC_11_20,
diff --git a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
index c1e9b38a13b0..9fbea724f491 100644
--- a/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
+++ b/media/java/android/media/tv/tuner/frontend/FrontendStatus.java
@@ -25,6 +25,9 @@ import android.media.tv.tuner.Lnb;
import android.media.tv.tuner.TunerVersionChecker;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
/**
* A Frontend Status class that contains the metrics of the active frontend.
@@ -1086,22 +1089,26 @@ public class FrontendStatus {
}
/**
- * Gets an array of all PLPs information of ATSC3 frontend, which includes both tuned and not
+ * Gets a list of all PLPs information of ATSC3 frontend, which includes both tuned and not
* tuned PLPs for currently watching service.
*
- * <p>This query is only supported by Tuner HAL 2.0 or higher. Unsupported version or if HAL
- * doesn't return all PLPs information will throw IllegalStateException. Use
- * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+ * <p>This query is only supported by Tuner HAL 2.0 or higher. Unsupported version will throw
+ * UnsupportedOperationException. Use {@link TunerVersionChecker#getTunerVersion()} to check
+ * the version.
+ *
+ * @return a list of all PLPs information. It is empty if HAL doesn't return all PLPs
+ * information status.
*/
- @SuppressLint("ArrayReturn")
@NonNull
- public Atsc3PlpInfo[] getAllAtsc3PlpInfo() {
- TunerVersionChecker.checkHigherOrEqualVersionTo(
- TunerVersionChecker.TUNER_VERSION_2_0, "Atsc3PlpInfo all status");
+ public List<Atsc3PlpInfo> getAllAtsc3PlpInfo() {
+ if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+ TunerVersionChecker.TUNER_VERSION_2_0, "Atsc3PlpInfo all status")) {
+ throw new UnsupportedOperationException("Atsc3PlpInfo all status is empty");
+ }
if (mAllPlpInfo == null) {
- throw new IllegalStateException("Atsc3PlpInfo all status is empty");
+ return Collections.EMPTY_LIST;
}
- return mAllPlpInfo;
+ return Arrays.asList(mAllPlpInfo);
}
/**
diff --git a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
index 726fe15b8edb..7e83d1545032 100644
--- a/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/Isdbs3FrontendSettings.java
@@ -36,8 +36,7 @@ import java.lang.annotation.RetentionPolicy;
@SystemApi
public class Isdbs3FrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "MODULATION_",
+ @IntDef(prefix = "MODULATION_",
value = {MODULATION_UNDEFINED, MODULATION_AUTO, MODULATION_MOD_BPSK,
MODULATION_MOD_QPSK, MODULATION_MOD_8PSK, MODULATION_MOD_16APSK,
MODULATION_MOD_32APSK})
@@ -75,8 +74,7 @@ public class Isdbs3FrontendSettings extends FrontendSettings {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true,
- prefix = "CODERATE_",
+ @IntDef(prefix = "CODERATE_",
value = {CODERATE_UNDEFINED, CODERATE_AUTO, CODERATE_1_3, CODERATE_2_5, CODERATE_1_2,
CODERATE_3_5, CODERATE_2_3, CODERATE_3_4, CODERATE_7_9, CODERATE_4_5,
CODERATE_5_6, CODERATE_7_8, CODERATE_9_10})
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
index 51ec5aeeb2eb..50294539e8f8 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbsFrontendSettings.java
@@ -54,8 +54,7 @@ public class IsdbsFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "MODULATION_",
+ @IntDef(prefix = "MODULATION_",
value = {MODULATION_UNDEFINED, MODULATION_AUTO, MODULATION_MOD_BPSK,
MODULATION_MOD_QPSK, MODULATION_MOD_TC8PSK})
@Retention(RetentionPolicy.SOURCE)
@@ -84,8 +83,7 @@ public class IsdbsFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "CODERATE_",
+ @IntDef(prefix = "CODERATE_",
value = {CODERATE_UNDEFINED, CODERATE_AUTO, CODERATE_1_2, CODERATE_2_3, CODERATE_3_4,
CODERATE_5_6, CODERATE_7_8})
@Retention(RetentionPolicy.SOURCE)
diff --git a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
index 89512a05674b..f08a51497f75 100644
--- a/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/IsdbtFrontendSettings.java
@@ -40,8 +40,7 @@ import java.lang.annotation.RetentionPolicy;
@SystemApi
public class IsdbtFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "MODULATION_",
+ @IntDef(prefix = "MODULATION_",
value = {MODULATION_UNDEFINED, MODULATION_AUTO, MODULATION_MOD_DQPSK,
MODULATION_MOD_QPSK, MODULATION_MOD_16QAM, MODULATION_MOD_64QAM})
@Retention(RetentionPolicy.SOURCE)
@@ -74,8 +73,7 @@ public class IsdbtFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "MODE_",
+ @IntDef(prefix = "MODE_",
value = {MODE_UNDEFINED, MODE_AUTO, MODE_1, MODE_2, MODE_3})
@Retention(RetentionPolicy.SOURCE)
public @interface Mode {}
@@ -103,8 +101,7 @@ public class IsdbtFrontendSettings extends FrontendSettings {
/** @hide */
- @IntDef(flag = true,
- prefix = "BANDWIDTH_",
+ @IntDef(prefix = "BANDWIDTH_",
value = {BANDWIDTH_UNDEFINED, BANDWIDTH_AUTO, BANDWIDTH_8MHZ, BANDWIDTH_7MHZ,
BANDWIDTH_6MHZ})
@Retention(RetentionPolicy.SOURCE)
@@ -132,7 +129,7 @@ public class IsdbtFrontendSettings extends FrontendSettings {
public static final int BANDWIDTH_6MHZ = FrontendIsdbtBandwidth.BANDWIDTH_6MHZ;
/** @hide */
- @IntDef(flag = true, prefix = "PARTIAL_RECEPTION_FLAG_",
+ @IntDef(prefix = "PARTIAL_RECEPTION_FLAG_",
value = {PARTIAL_RECEPTION_FLAG_UNDEFINED, PARTIAL_RECEPTION_FLAG_FALSE,
PARTIAL_RECEPTION_FLAG_TRUE})
@Retention(RetentionPolicy.SOURCE)
@@ -153,7 +150,7 @@ public class IsdbtFrontendSettings extends FrontendSettings {
public static final int PARTIAL_RECEPTION_FLAG_TRUE = FrontendIsdbtPartialReceptionFlag.TRUE;
/** @hide */
- @IntDef(flag = true, prefix = "TIME_INTERLEAVE_MODE_",
+ @IntDef(prefix = "TIME_INTERLEAVE_MODE_",
value = {TIME_INTERLEAVE_MODE_UNDEFINED, TIME_INTERLEAVE_MODE_AUTO,
TIME_INTERLEAVE_MODE_1_0, TIME_INTERLEAVE_MODE_1_4, TIME_INTERLEAVE_MODE_1_8,
TIME_INTERLEAVE_MODE_1_16, TIME_INTERLEAVE_MODE_2_0, TIME_INTERLEAVE_MODE_2_2,
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index d8f48c2cf0c6..20d711cf4c54 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -103,6 +103,7 @@ public class MtpDatabase implements AutoCloseable {
private int mDeviceType;
private String mHostType;
private boolean mSkipThumbForHost = false;
+ private volatile boolean mHostIsWindows = false;
private MtpServer mServer;
private MtpStorageManager mManager;
@@ -358,7 +359,7 @@ public class MtpDatabase implements AutoCloseable {
}
public void addStorage(StorageVolume storage) {
- MtpStorage mtpStorage = mManager.addMtpStorage(storage);
+ MtpStorage mtpStorage = mManager.addMtpStorage(storage, () -> mHostIsWindows);
mStorageMap.put(storage.getPath(), mtpStorage);
if (mServer != null) {
mServer.addStorage(mtpStorage);
@@ -413,6 +414,7 @@ public class MtpDatabase implements AutoCloseable {
}
mHostType = "";
mSkipThumbForHost = false;
+ mHostIsWindows = false;
}
@VisibleForNative
@@ -736,10 +738,12 @@ public class MtpDatabase implements AutoCloseable {
: MtpConstants.RESPONSE_GENERAL_ERROR);
case MtpConstants.DEVICE_PROPERTY_SESSION_INITIATOR_VERSION_INFO:
mHostType = stringValue;
+ Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
+ + "=" + stringValue);
if (stringValue.startsWith("Android/")) {
- Log.d(TAG, "setDeviceProperty." + Integer.toHexString(property)
- + "=" + stringValue);
mSkipThumbForHost = true;
+ } else if (stringValue.startsWith("Windows/")) {
+ mHostIsWindows = true;
}
return MtpConstants.RESPONSE_OK;
}
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 88c32a3ea72b..a3754e90a875 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -19,6 +19,8 @@ package android.mtp;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.storage.StorageVolume;
+import java.util.function.Supplier;
+
/**
* This class represents a storage unit on an MTP device.
* Used only for MTP support in USB responder mode.
@@ -33,14 +35,16 @@ public class MtpStorage {
private final boolean mRemovable;
private final long mMaxFileSize;
private final String mVolumeName;
+ private final Supplier<Boolean> mIsHostWindows;
- public MtpStorage(StorageVolume volume, int storageId) {
+ public MtpStorage(StorageVolume volume, int storageId, Supplier<Boolean> isHostWindows) {
mStorageId = storageId;
mPath = volume.getPath();
mDescription = volume.getDescription(null);
mRemovable = volume.isRemovable();
mMaxFileSize = volume.getMaxFileSize();
mVolumeName = volume.getMediaStoreVolumeName();
+ mIsHostWindows = isHostWindows;
}
/**
@@ -93,4 +97,13 @@ public class MtpStorage {
public String getVolumeName() {
return mVolumeName;
}
+
+ /**
+ * Returns true if the mtp host of this storage is Windows.
+ *
+ * @return is host Windows
+ */
+ public boolean isHostWindows() {
+ return mIsHostWindows.get();
+ }
}
diff --git a/media/java/android/mtp/MtpStorageManager.java b/media/java/android/mtp/MtpStorageManager.java
index 0bede0dccbed..e9426cf2ce31 100644
--- a/media/java/android/mtp/MtpStorageManager.java
+++ b/media/java/android/mtp/MtpStorageManager.java
@@ -18,7 +18,11 @@ package android.mtp;
import android.media.MediaFile;
import android.os.FileObserver;
+import android.os.SystemProperties;
import android.os.storage.StorageVolume;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
import android.util.Log;
import com.android.internal.util.Preconditions;
@@ -35,6 +39,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.function.Supplier;
/**
* MtpStorageManager provides functionality for listing, tracking, and notifying MtpServer of
@@ -199,7 +204,38 @@ public class MtpStorageManager {
}
public long getSize() {
- return mIsDir ? 0 : getPath().toFile().length();
+ return mIsDir ? 0 : maybeApplyTranscodeLengthWorkaround(getPath().toFile().length());
+ }
+
+ private long maybeApplyTranscodeLengthWorkaround(long length) {
+ // Windows truncates transferred files to the size advertised in the object property.
+ if (mStorage.isHostWindows() && isTranscodeMtpEnabled() && isFileTranscodeSupported()) {
+ // If the file supports transcoding, we double the returned size to accommodate
+ // the increase in size from transcoding to AVC. This is the same heuristic
+ // applied in the FUSE daemon (MediaProvider).
+ return length * 2;
+ }
+ return length;
+ }
+
+ private boolean isTranscodeMtpEnabled() {
+ return SystemProperties.getBoolean("sys.fuse.transcode_mtp", false);
+ }
+
+ private boolean isFileTranscodeSupported() {
+ // Check if the file supports transcoding by reading the |st_nlinks| struct stat
+ // field. This will be > 1 if the file supports transcoding. The FUSE daemon
+ // sets the field accordingly to enable the MTP stack workaround some Windows OS
+ // MTP client bug where they ignore the size returned as part of getting the MTP
+ // object, see MtpServer#doGetObject.
+ final Path path = getPath();
+ try {
+ StructStat stat = Os.stat(path.toString());
+ return stat.st_nlink > 1;
+ } catch (ErrnoException e) {
+ Log.w(TAG, "Failed to stat path: " + getPath() + ". Ignoring transcoding.");
+ return false;
+ }
}
public Path getPath() {
@@ -420,10 +456,12 @@ public class MtpStorageManager {
* @param volume Storage to add.
* @return the associated MtpStorage
*/
- public synchronized MtpStorage addMtpStorage(StorageVolume volume) {
+ public synchronized MtpStorage addMtpStorage(StorageVolume volume,
+ Supplier<Boolean> isHostWindows) {
int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1;
- MtpStorage storage = new MtpStorage(volume, storageId);
- MtpObject root = new MtpObject(storage.getPath(), storageId, storage, null, true);
+ MtpStorage storage = new MtpStorage(volume, storageId, isHostWindows);
+ MtpObject root = new MtpObject(storage.getPath(), storageId, storage, /* parent= */ null,
+ /* isDir= */ true);
mRoots.put(storageId, root);
return storage;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BluetoothProfileConnectionInfoTest.java
index fd66d3b9904e..f23794b50543 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BluetoothProfileConnectionInfoTest.java
@@ -19,7 +19,7 @@ package com.android.mediaframeworktest.unit;
import static org.junit.Assert.assertEquals;
import android.bluetooth.BluetoothProfile;
-import android.media.BtProfileConnectionInfo;
+import android.media.BluetoothProfileConnectionInfo;
import androidx.test.runner.AndroidJUnit4;
@@ -27,22 +27,24 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
-public class BtProfileConnectionInfoTest {
+public class BluetoothProfileConnectionInfoTest {
@Test
public void testCoverageA2dp() {
final boolean supprNoisy = false;
final int volume = 42;
- final BtProfileConnectionInfo info = BtProfileConnectionInfo.a2dpInfo(supprNoisy, volume);
+ final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo
+ .createA2dpInfo(supprNoisy, volume);
assertEquals(info.getProfile(), BluetoothProfile.A2DP);
- assertEquals(info.getSuppressNoisyIntent(), supprNoisy);
+ assertEquals(info.isSuppressNoisyIntent(), supprNoisy);
assertEquals(info.getVolume(), volume);
}
@Test
public void testCoverageA2dpSink() {
final int volume = 42;
- final BtProfileConnectionInfo info = BtProfileConnectionInfo.a2dpSinkInfo(volume);
+ final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo
+ .createA2dpSinkInfo(volume);
assertEquals(info.getProfile(), BluetoothProfile.A2DP_SINK);
assertEquals(info.getVolume(), volume);
}
@@ -50,20 +52,21 @@ public class BtProfileConnectionInfoTest {
@Test
public void testCoveragehearingAid() {
final boolean supprNoisy = true;
- final BtProfileConnectionInfo info = BtProfileConnectionInfo.hearingAidInfo(supprNoisy);
+ final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo
+ .createHearingAidInfo(supprNoisy);
assertEquals(info.getProfile(), BluetoothProfile.HEARING_AID);
- assertEquals(info.getSuppressNoisyIntent(), supprNoisy);
+ assertEquals(info.isSuppressNoisyIntent(), supprNoisy);
}
@Test
public void testCoverageLeAudio() {
final boolean supprNoisy = false;
final boolean isLeOutput = true;
- final BtProfileConnectionInfo info = BtProfileConnectionInfo.leAudio(supprNoisy,
- isLeOutput);
+ final BluetoothProfileConnectionInfo info = BluetoothProfileConnectionInfo
+ .createLeAudioInfo(supprNoisy, isLeOutput);
assertEquals(info.getProfile(), BluetoothProfile.LE_AUDIO);
- assertEquals(info.getSuppressNoisyIntent(), supprNoisy);
- assertEquals(info.getIsLeOutput(), isLeOutput);
+ assertEquals(info.isSuppressNoisyIntent(), supprNoisy);
+ assertEquals(info.isLeOutput(), isLeOutput);
}
}
diff --git a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
index abdc7e559fb3..a6a5568ac8f4 100644
--- a/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
+++ b/media/tests/MtpTests/src/android/mtp/MtpStorageManagerTest.java
@@ -160,10 +160,11 @@ public class MtpStorageManagerTest {
Log.d(TAG, "sendObjectInfoChanged: " + id);
objectsInfoChanged.add(id);
}
- }, null);
+ }, /* subdirectories= */ null);
- mainMtpStorage = manager.addMtpStorage(mainStorage);
- secondaryMtpStorage = manager.addMtpStorage(secondaryStorage);
+ mainMtpStorage = manager.addMtpStorage(mainStorage, /* isHostWindows= */ () -> false);
+ secondaryMtpStorage = manager.addMtpStorage(secondaryStorage,
+ /* isHostWindows= */ () -> false);
}
@After
diff --git a/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java b/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
index 414de89f8218..09573909c288 100644
--- a/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
+++ b/media/tests/aidltests/src/com/android/media/AidlConversionUnitTests.java
@@ -16,8 +16,18 @@
package android.media.audio.common;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
import android.media.AudioAttributes;
+import android.media.AudioDescriptor;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
+import android.media.AudioProfile;
import android.media.AudioSystem;
import android.media.AudioTrack;
import android.media.MediaFormat;
@@ -25,11 +35,12 @@ import android.platform.test.annotations.Presubmit;
import androidx.test.runner.AndroidJUnit4;
-import static org.junit.Assert.*;
-
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.Arrays;
+
/**
* Unit tests for AidlConversion utilities.
*
@@ -417,10 +428,102 @@ public final class AidlConversionUnitTests {
() -> AidlConversion.legacy2aidl_audio_usage_t_AudioUsage(sInvalidValue));
}
+ @Test
+ public void testAudioDescriptorConversion_Default() {
+ ExtraAudioDescriptor aidl = createDefaultDescriptor();
+ AudioDescriptor audioDescriptor =
+ AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(aidl);
+ assertEquals(AudioDescriptor.STANDARD_NONE, audioDescriptor.getStandard());
+ assertEquals(
+ AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, audioDescriptor.getEncapsulationType());
+ assertTrue(Arrays.equals(new byte[]{}, audioDescriptor.getDescriptor()));
+
+ ExtraAudioDescriptor reconstructedExtraDescriptor =
+ AidlConversion.api2aidl_AudioDescriptor_ExtraAudioDescriptor(audioDescriptor);
+ assertEquals(aidl, reconstructedExtraDescriptor);
+ }
+
+ @Test
+ public void testAudioDescriptorConversion() {
+ ExtraAudioDescriptor aidl = createEncapsulationDescriptor(new byte[]{0x05, 0x18, 0x4A});
+ AudioDescriptor audioDescriptor =
+ AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(aidl);
+ assertEquals(AudioDescriptor.STANDARD_EDID, audioDescriptor.getStandard());
+ assertEquals(AudioProfile.AUDIO_ENCAPSULATION_TYPE_IEC61937,
+ audioDescriptor.getEncapsulationType());
+ assertTrue(Arrays.equals(new byte[]{0x05, 0x18, 0x4A}, audioDescriptor.getDescriptor()));
+
+ ExtraAudioDescriptor reconstructedExtraDescriptor =
+ AidlConversion.api2aidl_AudioDescriptor_ExtraAudioDescriptor(audioDescriptor);
+ assertEquals(aidl, reconstructedExtraDescriptor);
+ }
+
+ @Test
+ public void testAudioDeviceAttributesConversion_Default() {
+ AudioDeviceAttributes attributes =
+ new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_DEFAULT, "myAddress");
+ AudioPort port = AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(attributes);
+ assertEquals("", port.name);
+ assertEquals(0, port.extraAudioDescriptors.length);
+ assertEquals("myAddress", port.ext.getDevice().device.address.getId());
+ assertEquals("", port.ext.getDevice().device.type.connection);
+ assertEquals(AudioDeviceType.OUT_DEFAULT, port.ext.getDevice().device.type.type);
+ }
+
+ @Test
+ public void testAudioDeviceAttributesConversion() {
+ AudioDescriptor audioDescriptor1 =
+ AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(
+ createEncapsulationDescriptor(new byte[]{0x05, 0x18, 0x4A}));
+
+ AudioDescriptor audioDescriptor2 =
+ AidlConversion.aidl2api_ExtraAudioDescriptor_AudioDescriptor(
+ createDefaultDescriptor());
+
+ AudioDeviceAttributes attributes =
+ new AudioDeviceAttributes(AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_HDMI_ARC, "myAddress", "myName", new ArrayList<>(),
+ new ArrayList<>(Arrays.asList(audioDescriptor1, audioDescriptor2)));
+ AudioPort port = AidlConversion.api2aidl_AudioDeviceAttributes_AudioPort(
+ attributes);
+ assertEquals("myName", port.name);
+ assertEquals(2, port.extraAudioDescriptors.length);
+ assertEquals(AudioStandard.EDID, port.extraAudioDescriptors[0].standard);
+ assertEquals(AudioEncapsulationType.IEC61937,
+ port.extraAudioDescriptors[0].encapsulationType);
+ assertTrue(Arrays.equals(new byte[]{0x05, 0x18, 0x4A},
+ port.extraAudioDescriptors[0].audioDescriptor));
+ assertEquals(AudioStandard.NONE, port.extraAudioDescriptors[1].standard);
+ assertEquals(AudioEncapsulationType.NONE,
+ port.extraAudioDescriptors[1].encapsulationType);
+ assertTrue(Arrays.equals(new byte[]{},
+ port.extraAudioDescriptors[1].audioDescriptor));
+ assertEquals("myAddress", port.ext.getDevice().device.address.getId());
+ assertEquals(AudioDeviceDescription.CONNECTION_HDMI_ARC,
+ port.ext.getDevice().device.type.connection);
+ assertEquals(AudioDeviceType.OUT_DEVICE, port.ext.getDevice().device.type.type);
+ }
+
private static AudioFormatDescription createPcm16FormatAidl() {
final AudioFormatDescription aidl = new AudioFormatDescription();
aidl.type = AudioFormatType.PCM;
aidl.pcm = PcmType.INT_16_BIT;
return aidl;
}
+
+ private static ExtraAudioDescriptor createDefaultDescriptor() {
+ ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
+ extraDescriptor.standard = AudioStandard.NONE;
+ extraDescriptor.encapsulationType = AudioEncapsulationType.NONE;
+ extraDescriptor.audioDescriptor = new byte[]{};
+ return extraDescriptor;
+ }
+
+ private static ExtraAudioDescriptor createEncapsulationDescriptor(byte[] audioDescriptor) {
+ ExtraAudioDescriptor extraDescriptor = new ExtraAudioDescriptor();
+ extraDescriptor.standard = AudioStandard.EDID;
+ extraDescriptor.encapsulationType = AudioEncapsulationType.IEC61937;
+ extraDescriptor.audioDescriptor = audioDescriptor;
+ return extraDescriptor;
+ }
}
diff --git a/packages/ConnectivityT/framework-t/Android.bp b/packages/ConnectivityT/framework-t/Android.bp
index 54538d91a5cf..6329565ca567 100644
--- a/packages/ConnectivityT/framework-t/Android.bp
+++ b/packages/ConnectivityT/framework-t/Android.bp
@@ -158,7 +158,6 @@ filegroup {
name: "framework-connectivity-tiramisu-sources",
srcs: [
":framework-connectivity-ethernet-sources",
- ":framework-connectivity-ipsec-sources",
":framework-connectivity-netstats-sources",
],
visibility: ["//frameworks/base"],
@@ -167,6 +166,7 @@ filegroup {
filegroup {
name: "framework-connectivity-tiramisu-updatable-sources",
srcs: [
+ ":framework-connectivity-ipsec-sources",
":framework-connectivity-nsd-sources",
":framework-connectivity-tiramisu-internal-sources",
],
diff --git a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
index 630f902ecfd7..577ac5466692 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java
@@ -48,5 +48,14 @@ public final class ConnectivityFrameworkInitializerTiramisu {
return new NsdManager(context, service);
}
);
+
+ SystemServiceRegistry.registerContextAwareService(
+ Context.IPSEC_SERVICE,
+ IpSecManager.class,
+ (context, serviceBinder) -> {
+ IIpSecService service = IIpSecService.Stub.asInterface(serviceBinder);
+ return new IpSecManager(context, service);
+ }
+ );
}
}
diff --git a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
index f472d563c477..e0ce081c0276 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/EthernetManager.java
@@ -358,6 +358,7 @@ public class EthernetManager {
return proxy;
}
+ @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS)
private void updateConfiguration(
@NonNull String iface,
@NonNull EthernetNetworkUpdateRequest request,
@@ -372,6 +373,7 @@ public class EthernetManager {
}
}
+ @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS)
private void connectNetwork(
@NonNull String iface,
@Nullable @CallbackExecutor Executor executor,
@@ -385,6 +387,7 @@ public class EthernetManager {
}
}
+ @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS)
private void disconnectNetwork(
@NonNull String iface,
@Nullable @CallbackExecutor Executor executor,
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
index 0f21e55b9f27..512fbcee9330 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdManager.java
@@ -16,6 +16,9 @@
package android.net.nsd;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemService;
@@ -23,15 +26,22 @@ import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkRequest;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.util.Objects;
@@ -278,9 +288,180 @@ public final class NsdManager {
private final SparseArray mListenerMap = new SparseArray();
private final SparseArray<NsdServiceInfo> mServiceMap = new SparseArray<>();
private final Object mMapLock = new Object();
+ // Map of listener key sent by client -> per-network discovery tracker
+ @GuardedBy("mPerNetworkDiscoveryMap")
+ private final ArrayMap<Integer, PerNetworkDiscoveryTracker>
+ mPerNetworkDiscoveryMap = new ArrayMap<>();
private final ServiceHandler mHandler;
+ private class PerNetworkDiscoveryTracker {
+ final String mServiceType;
+ final int mProtocolType;
+ final DiscoveryListener mBaseListener;
+ final ArrayMap<Network, DelegatingDiscoveryListener> mPerNetworkListeners =
+ new ArrayMap<>();
+
+ final NetworkCallback mNetworkCb = new NetworkCallback() {
+ @Override
+ public void onAvailable(@NonNull Network network) {
+ final DelegatingDiscoveryListener wrappedListener = new DelegatingDiscoveryListener(
+ network, mBaseListener);
+ mPerNetworkListeners.put(network, wrappedListener);
+ discoverServices(mServiceType, mProtocolType, network, wrappedListener);
+ }
+
+ @Override
+ public void onLost(@NonNull Network network) {
+ final DelegatingDiscoveryListener listener = mPerNetworkListeners.get(network);
+ if (listener == null) return;
+ listener.notifyAllServicesLost();
+ // Listener will be removed from map in discovery stopped callback
+ stopServiceDiscovery(listener);
+ }
+ };
+
+ // Accessed from mHandler
+ private boolean mStopRequested;
+
+ public void start(@NonNull NetworkRequest request) {
+ final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+ cm.registerNetworkCallback(request, mNetworkCb, mHandler);
+ mHandler.post(() -> mBaseListener.onDiscoveryStarted(mServiceType));
+ }
+
+ /**
+ * Stop discovery on all networks tracked by this class.
+ *
+ * This will request all underlying listeners to stop, and the last one to stop will call
+ * onDiscoveryStopped or onStopDiscoveryFailed.
+ *
+ * Must be called on the handler thread.
+ */
+ public void requestStop() {
+ mHandler.post(() -> {
+ mStopRequested = true;
+ final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+ cm.unregisterNetworkCallback(mNetworkCb);
+ if (mPerNetworkListeners.size() == 0) {
+ mBaseListener.onDiscoveryStopped(mServiceType);
+ return;
+ }
+ for (int i = 0; i < mPerNetworkListeners.size(); i++) {
+ final DelegatingDiscoveryListener listener = mPerNetworkListeners.valueAt(i);
+ stopServiceDiscovery(listener);
+ }
+ });
+ }
+
+ private PerNetworkDiscoveryTracker(String serviceType, int protocolType,
+ DiscoveryListener baseListener) {
+ mServiceType = serviceType;
+ mProtocolType = protocolType;
+ mBaseListener = baseListener;
+ }
+
+ /**
+ * Subset of NsdServiceInfo that is tracked to generate service lost notifications when a
+ * network is lost.
+ *
+ * Service lost notifications only contain service name, type and network, so only track
+ * that information (Network is known from the listener). This also implements
+ * equals/hashCode for usage in maps.
+ */
+ private class TrackedNsdInfo {
+ private final String mServiceName;
+ private final String mServiceType;
+ TrackedNsdInfo(NsdServiceInfo info) {
+ mServiceName = info.getServiceName();
+ mServiceType = info.getServiceType();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mServiceName, mServiceType);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof TrackedNsdInfo)) return false;
+ final TrackedNsdInfo other = (TrackedNsdInfo) obj;
+ return Objects.equals(mServiceName, other.mServiceName)
+ && Objects.equals(mServiceType, other.mServiceType);
+ }
+ }
+
+ private class DelegatingDiscoveryListener implements DiscoveryListener {
+ private final Network mNetwork;
+ private final DiscoveryListener mWrapped;
+ private final ArraySet<TrackedNsdInfo> mFoundInfo = new ArraySet<>();
+
+ private DelegatingDiscoveryListener(Network network, DiscoveryListener listener) {
+ mNetwork = network;
+ mWrapped = listener;
+ }
+
+ void notifyAllServicesLost() {
+ for (int i = 0; i < mFoundInfo.size(); i++) {
+ final TrackedNsdInfo trackedInfo = mFoundInfo.valueAt(i);
+ final NsdServiceInfo serviceInfo = new NsdServiceInfo(
+ trackedInfo.mServiceName, trackedInfo.mServiceType);
+ serviceInfo.setNetwork(mNetwork);
+ mWrapped.onServiceLost(serviceInfo);
+ }
+ }
+
+ @Override
+ public void onStartDiscoveryFailed(String serviceType, int errorCode) {
+ // The delegated listener is used when NsdManager takes care of starting/stopping
+ // discovery on multiple networks. Failure to start on one network is not a global
+ // failure to be reported up, as other networks may succeed: just log.
+ Log.e(TAG, "Failed to start discovery for " + serviceType + " on " + mNetwork
+ + " with code " + errorCode);
+ mPerNetworkListeners.remove(mNetwork);
+ }
+
+ @Override
+ public void onDiscoveryStarted(String serviceType) {
+ // Wrapped listener was called upon registration, it is not called for discovery
+ // on each network
+ }
+
+ @Override
+ public void onStopDiscoveryFailed(String serviceType, int errorCode) {
+ Log.e(TAG, "Failed to stop discovery for " + serviceType + " on " + mNetwork
+ + " with code " + errorCode);
+ mPerNetworkListeners.remove(mNetwork);
+ if (mStopRequested && mPerNetworkListeners.size() == 0) {
+ // Do not report onStopDiscoveryFailed when some underlying listeners failed:
+ // this does not mean that all listeners did, and onStopDiscoveryFailed is not
+ // actionable anyway. Just report that discovery stopped.
+ mWrapped.onDiscoveryStopped(serviceType);
+ }
+ }
+
+ @Override
+ public void onDiscoveryStopped(String serviceType) {
+ mPerNetworkListeners.remove(mNetwork);
+ if (mStopRequested && mPerNetworkListeners.size() == 0) {
+ mWrapped.onDiscoveryStopped(serviceType);
+ }
+ }
+
+ @Override
+ public void onServiceFound(NsdServiceInfo serviceInfo) {
+ mFoundInfo.add(new TrackedNsdInfo(serviceInfo));
+ mWrapped.onServiceFound(serviceInfo);
+ }
+
+ @Override
+ public void onServiceLost(NsdServiceInfo serviceInfo) {
+ mFoundInfo.remove(new TrackedNsdInfo(serviceInfo));
+ mWrapped.onServiceLost(serviceInfo);
+ }
+ }
+ }
+
/**
* Create a new Nsd instance. Applications use
* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
@@ -634,6 +815,14 @@ public final class NsdManager {
}
/**
+ * Same as {@link #discoverServices(String, int, Network, DiscoveryListener)} with a null
+ * {@link Network}.
+ */
+ public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
+ discoverServices(serviceType, protocolType, (Network) null, listener);
+ }
+
+ /**
* Initiate service discovery to browse for instances of a service type. Service discovery
* consumes network bandwidth and will continue until the application calls
* {@link #stopServiceDiscovery}.
@@ -657,11 +846,13 @@ public final class NsdManager {
* @param serviceType The service type being discovered. Examples include "_http._tcp" for
* http services or "_ipp._tcp" for printers
* @param protocolType The service discovery protocol
+ * @param network Network to discover services on, or null to discover on all available networks
* @param listener The listener notifies of a successful discovery and is used
* to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
* Cannot be null. Cannot be in use for an active service discovery.
*/
- public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) {
+ public void discoverServices(@NonNull String serviceType, int protocolType,
+ @Nullable Network network, @NonNull DiscoveryListener listener) {
if (TextUtils.isEmpty(serviceType)) {
throw new IllegalArgumentException("Service type cannot be empty");
}
@@ -669,6 +860,7 @@ public final class NsdManager {
NsdServiceInfo s = new NsdServiceInfo();
s.setServiceType(serviceType);
+ s.setNetwork(network);
int key = putListener(listener, s);
try {
@@ -679,6 +871,67 @@ public final class NsdManager {
}
/**
+ * Initiate service discovery to browse for instances of a service type. Service discovery
+ * consumes network bandwidth and will continue until the application calls
+ * {@link #stopServiceDiscovery}.
+ *
+ * <p> The function call immediately returns after sending a request to start service
+ * discovery to the framework. The application is notified of a success to initiate
+ * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure
+ * through {@link DiscoveryListener#onStartDiscoveryFailed}.
+ *
+ * <p> Upon successful start, application is notified when a service is found with
+ * {@link DiscoveryListener#onServiceFound} or when a service is lost with
+ * {@link DiscoveryListener#onServiceLost}.
+ *
+ * <p> Upon failure to start, service discovery is not active and application does
+ * not need to invoke {@link #stopServiceDiscovery}
+ *
+ * <p> The application should call {@link #stopServiceDiscovery} when discovery of this
+ * service type is no longer required, and/or whenever the application is paused or
+ * stopped.
+ *
+ * <p> During discovery, new networks may connect or existing networks may disconnect - for
+ * example if wifi is reconnected. When a service was found on a network that disconnects,
+ * {@link DiscoveryListener#onServiceLost} will be called. If a new network connects that
+ * matches the {@link NetworkRequest}, {@link DiscoveryListener#onServiceFound} will be called
+ * for services found on that network. Applications that do not want to track networks
+ * themselves are encouraged to use this method instead of other overloads of
+ * {@code discoverServices}, as they will receive proper notifications when a service becomes
+ * available or unavailable due to network changes.
+ *
+ * @param serviceType The service type being discovered. Examples include "_http._tcp" for
+ * http services or "_ipp._tcp" for printers
+ * @param protocolType The service discovery protocol
+ * @param networkRequest Request specifying networks that should be considered when discovering
+ * @param listener The listener notifies of a successful discovery and is used
+ * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}.
+ * Cannot be null. Cannot be in use for an active service discovery.
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
+ public void discoverServices(@NonNull String serviceType, int protocolType,
+ @NonNull NetworkRequest networkRequest, @NonNull DiscoveryListener listener) {
+ if (TextUtils.isEmpty(serviceType)) {
+ throw new IllegalArgumentException("Service type cannot be empty");
+ }
+ Objects.requireNonNull(networkRequest, "NetworkRequest cannot be null");
+ checkProtocol(protocolType);
+
+ NsdServiceInfo s = new NsdServiceInfo();
+ s.setServiceType(serviceType);
+
+ final int baseListenerKey = putListener(listener, s);
+
+ final PerNetworkDiscoveryTracker discoveryInfo = new PerNetworkDiscoveryTracker(
+ serviceType, protocolType, listener);
+
+ synchronized (mPerNetworkDiscoveryMap) {
+ mPerNetworkDiscoveryMap.put(baseListenerKey, discoveryInfo);
+ discoveryInfo.start(networkRequest);
+ }
+ }
+
+ /**
* Stop service discovery initiated with {@link #discoverServices}. An active service
* discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted}
* and it stays active until the application invokes a stop service discovery. A successful
@@ -696,6 +949,14 @@ public final class NsdManager {
*/
public void stopServiceDiscovery(DiscoveryListener listener) {
int id = getListenerKey(listener);
+ // If this is a PerNetworkDiscovery request, handle it as such
+ synchronized (mPerNetworkDiscoveryMap) {
+ final PerNetworkDiscoveryTracker info = mPerNetworkDiscoveryMap.get(id);
+ if (info != null) {
+ info.requestStop();
+ return;
+ }
+ }
try {
mService.stopDiscovery(id);
} catch (RemoteException e) {
diff --git a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
index 0946499f164f..8506db1fbe01 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/nsd/NsdServiceInfo.java
@@ -17,7 +17,9 @@
package android.net.nsd;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
+import android.net.Network;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
@@ -49,6 +51,9 @@ public final class NsdServiceInfo implements Parcelable {
private int mPort;
+ @Nullable
+ private Network mNetwork;
+
public NsdServiceInfo() {
}
@@ -307,18 +312,37 @@ public final class NsdServiceInfo implements Parcelable {
return txtRecord;
}
- public String toString() {
- StringBuffer sb = new StringBuffer();
+ /**
+ * Get the network where the service can be found.
+ *
+ * This is never null if this {@link NsdServiceInfo} was obtained from
+ * {@link NsdManager#discoverServices} or {@link NsdManager#resolveService}.
+ */
+ @Nullable
+ public Network getNetwork() {
+ return mNetwork;
+ }
+ /**
+ * Set the network where the service can be found.
+ * @param network The network, or null to search for, or to announce, the service on all
+ * connected networks.
+ */
+ public void setNetwork(@Nullable Network network) {
+ mNetwork = network;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
sb.append("name: ").append(mServiceName)
.append(", type: ").append(mServiceType)
.append(", host: ").append(mHost)
- .append(", port: ").append(mPort);
+ .append(", port: ").append(mPort)
+ .append(", network: ").append(mNetwork);
byte[] txtRecord = getTxtRecord();
- if (txtRecord != null) {
- sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
- }
+ sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8));
return sb.toString();
}
@@ -352,6 +376,8 @@ public final class NsdServiceInfo implements Parcelable {
}
dest.writeString(key);
}
+
+ dest.writeParcelable(mNetwork, 0);
}
/** Implement the Parcelable interface */
@@ -381,6 +407,7 @@ public final class NsdServiceInfo implements Parcelable {
}
info.mTxtRecord.put(in.readString(), valueArray);
}
+ info.mNetwork = in.readParcelable(null, Network.class);
return info;
}
diff --git a/packages/ConnectivityT/service/Android.bp b/packages/ConnectivityT/service/Android.bp
index 24bc91d91ef7..d2d6ef0cbbb1 100644
--- a/packages/ConnectivityT/service/Android.bp
+++ b/packages/ConnectivityT/service/Android.bp
@@ -83,7 +83,6 @@ filegroup {
name: "services.connectivity-tiramisu-sources",
srcs: [
":services.connectivity-ethernet-sources",
- ":services.connectivity-ipsec-sources",
":services.connectivity-netstats-sources",
],
path: "src",
@@ -93,6 +92,7 @@ filegroup {
filegroup {
name: "services.connectivity-tiramisu-updatable-sources",
srcs: [
+ ":services.connectivity-ipsec-sources",
":services.connectivity-nsd-sources",
],
path: "src",
diff --git a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
index 179d9459fd84..4bc40eae4404 100644
--- a/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/IpSecService.java
@@ -1008,16 +1008,10 @@ public class IpSecService extends IIpSecService.Stub {
*
* @param context Binder context for this service
*/
- private IpSecService(Context context) {
+ public IpSecService(Context context) {
this(context, new Dependencies());
}
- static IpSecService create(Context context)
- throws InterruptedException {
- final IpSecService service = new IpSecService(context);
- return service;
- }
-
@NonNull
private AppOpsManager getAppOpsManager() {
AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
@@ -1054,26 +1048,6 @@ public class IpSecService extends IIpSecService.Stub {
}
}
- /** Called by system server when system is ready. */
- public void systemReady() {
- if (isNetdAlive()) {
- Log.d(TAG, "IpSecService is ready");
- } else {
- Log.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!");
- }
- }
-
- synchronized boolean isNetdAlive() {
- try {
- if (mNetd == null) {
- return false;
- }
- return mNetd.isAlive();
- } catch (RemoteException re) {
- return false;
- }
- }
-
/**
* Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be
* a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1.
@@ -1896,7 +1870,6 @@ public class IpSecService extends IIpSecService.Stub {
mContext.enforceCallingOrSelfPermission(DUMP, TAG);
pw.println("IpSecService dump:");
- pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
pw.println();
pw.println("mUserResourceTracker:");
diff --git a/packages/ConnectivityT/service/src/com/android/server/NsdService.java b/packages/ConnectivityT/service/src/com/android/server/NsdService.java
index 497107dbf989..ddf6d2c4ab15 100644
--- a/packages/ConnectivityT/service/src/com/android/server/NsdService.java
+++ b/packages/ConnectivityT/service/src/com/android/server/NsdService.java
@@ -19,6 +19,9 @@ package com.android.server;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
import android.net.nsd.INsdManager;
import android.net.nsd.INsdManagerCallback;
import android.net.nsd.INsdServiceConnector;
@@ -44,6 +47,9 @@ import com.android.net.module.util.DnsSdTxtRecord;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
@@ -60,6 +66,7 @@ public class NsdService extends INsdManager.Stub {
private static final boolean DBG = true;
private static final long CLEANUP_DELAY_MS = 10000;
+ private static final int IFACE_IDX_ANY = 0;
private final Context mContext;
private final NsdStateMachine mNsdStateMachine;
@@ -297,7 +304,7 @@ public class NsdService extends INsdManager.Stub {
maybeStartDaemon();
id = getUniqueId();
- if (discoverServices(id, args.serviceInfo.getServiceType())) {
+ if (discoverServices(id, args.serviceInfo)) {
if (DBG) {
Log.d(TAG, "Discover " + msg.arg2 + " " + id
+ args.serviceInfo.getServiceType());
@@ -430,13 +437,38 @@ public class NsdService extends INsdManager.Stub {
}
switch (code) {
case NativeResponseCode.SERVICE_FOUND:
- /* NNN uniqueId serviceName regType domain */
+ /* NNN uniqueId serviceName regType domain interfaceIdx netId */
servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
+ final int foundNetId;
+ try {
+ foundNetId = Integer.parseInt(cooked[6]);
+ } catch (NumberFormatException e) {
+ Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]);
+ break;
+ }
+ if (foundNetId == 0L) {
+ // Ignore services that do not have a Network: they are not usable
+ // by apps, as they would need privileged permissions to use
+ // interfaces that do not have an associated Network.
+ break;
+ }
+ servInfo.setNetwork(new Network(foundNetId));
clientInfo.onServiceFound(clientId, servInfo);
break;
case NativeResponseCode.SERVICE_LOST:
- /* NNN uniqueId serviceName regType domain */
+ /* NNN uniqueId serviceName regType domain interfaceIdx netId */
+ final int lostNetId;
+ try {
+ lostNetId = Integer.parseInt(cooked[6]);
+ } catch (NumberFormatException e) {
+ Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]);
+ break;
+ }
servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
+ // The network could be null if it was torn down when the service is lost
+ // TODO: avoid returning null in that case, possibly by remembering found
+ // services on the same interface index and their network at the time
+ servInfo.setNetwork(lostNetId == 0 ? null : new Network(lostNetId));
clientInfo.onServiceLost(clientId, servInfo);
break;
case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
@@ -461,7 +493,7 @@ public class NsdService extends INsdManager.Stub {
/* NNN regId errorCode */
break;
case NativeResponseCode.SERVICE_RESOLVED:
- /* NNN resolveId fullName hostName port txtlen txtdata */
+ /* NNN resolveId fullName hostName port txtlen txtdata interfaceIdx */
int index = 0;
while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
if (cooked[2].charAt(index) == '\\') {
@@ -473,6 +505,7 @@ public class NsdService extends INsdManager.Stub {
Log.e(TAG, "Invalid service found " + raw);
break;
}
+
String name = cooked[2].substring(0, index);
String rest = cooked[2].substring(index);
String type = rest.replace(".local.", "");
@@ -483,12 +516,13 @@ public class NsdService extends INsdManager.Stub {
clientInfo.mResolvedService.setServiceType(type);
clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
clientInfo.mResolvedService.setTxtRecords(cooked[6]);
+ // Network will be added after SERVICE_GET_ADDR_SUCCESS
stopResolveService(id);
removeRequestMap(clientId, id, clientInfo);
int id2 = getUniqueId();
- if (getAddrInfo(id2, cooked[3])) {
+ if (getAddrInfo(id2, cooked[3], cooked[7] /* interfaceIdx */)) {
storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
} else {
clientInfo.onResolveServiceFailed(
@@ -513,12 +547,31 @@ public class NsdService extends INsdManager.Stub {
clientId, NsdManager.FAILURE_INTERNAL_ERROR);
break;
case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
- /* NNN resolveId hostname ttl addr */
+ /* NNN resolveId hostname ttl addr interfaceIdx netId */
+ Network network = null;
+ try {
+ final int netId = Integer.parseInt(cooked[6]);
+ network = netId == 0L ? null : new Network(netId);
+ } catch (NumberFormatException e) {
+ Log.wtf(TAG, "Invalid network in GET_ADDR_SUCCESS: " + cooked[6], e);
+ }
+
+ InetAddress serviceHost = null;
try {
- clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
+ serviceHost = InetAddress.getByName(cooked[4]);
+ } catch (UnknownHostException e) {
+ Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e);
+ }
+
+ // If the resolved service is on an interface without a network, consider it
+ // as a failure: it would not be usable by apps as they would need
+ // privileged permissions.
+ if (network != null && serviceHost != null) {
+ clientInfo.mResolvedService.setHost(serviceHost);
+ clientInfo.mResolvedService.setNetwork(network);
clientInfo.onResolveServiceSucceeded(
clientId, clientInfo.mResolvedService);
- } catch (java.net.UnknownHostException e) {
+ } else {
clientInfo.onResolveServiceFailed(
clientId, NsdManager.FAILURE_INTERNAL_ERROR);
}
@@ -815,8 +868,15 @@ public class NsdService extends INsdManager.Stub {
return mDaemon.execute("update", regId, t.size(), t.getRawData());
}
- private boolean discoverServices(int discoveryId, String serviceType) {
- return mDaemon.execute("discover", discoveryId, serviceType);
+ private boolean discoverServices(int discoveryId, NsdServiceInfo serviceInfo) {
+ final Network network = serviceInfo.getNetwork();
+ final int discoverInterface = getNetworkInterfaceIndex(network);
+ if (network != null && discoverInterface == IFACE_IDX_ANY) {
+ Log.e(TAG, "Interface to discover service on not found");
+ return false;
+ }
+ return mDaemon.execute("discover", discoveryId, serviceInfo.getServiceType(),
+ discoverInterface);
}
private boolean stopServiceDiscovery(int discoveryId) {
@@ -824,17 +884,61 @@ public class NsdService extends INsdManager.Stub {
}
private boolean resolveService(int resolveId, NsdServiceInfo service) {
- String name = service.getServiceName();
- String type = service.getServiceType();
- return mDaemon.execute("resolve", resolveId, name, type, "local.");
+ final String name = service.getServiceName();
+ final String type = service.getServiceType();
+ final Network network = service.getNetwork();
+ final int resolveInterface = getNetworkInterfaceIndex(network);
+ if (network != null && resolveInterface == IFACE_IDX_ANY) {
+ Log.e(TAG, "Interface to resolve service on not found");
+ return false;
+ }
+ return mDaemon.execute("resolve", resolveId, name, type, "local.", resolveInterface);
+ }
+
+ /**
+ * Guess the interface to use to resolve or discover a service on a specific network.
+ *
+ * This is an imperfect guess, as for example the network may be gone or not yet fully
+ * registered. This is fine as failing is correct if the network is gone, and a client
+ * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also
+ * this is to support the legacy mdnsresponder implementation, which historically resolved
+ * services on an unspecified network.
+ */
+ private int getNetworkInterfaceIndex(Network network) {
+ if (network == null) return IFACE_IDX_ANY;
+
+ final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
+ if (cm == null) {
+ Log.wtf(TAG, "No ConnectivityManager for resolveService");
+ return IFACE_IDX_ANY;
+ }
+ final LinkProperties lp = cm.getLinkProperties(network);
+ if (lp == null) return IFACE_IDX_ANY;
+
+ // Only resolve on non-stacked interfaces
+ final NetworkInterface iface;
+ try {
+ iface = NetworkInterface.getByName(lp.getInterfaceName());
+ } catch (SocketException e) {
+ Log.e(TAG, "Error querying interface", e);
+ return IFACE_IDX_ANY;
+ }
+
+ if (iface == null) {
+ Log.e(TAG, "Interface not found: " + lp.getInterfaceName());
+ return IFACE_IDX_ANY;
+ }
+
+ return iface.getIndex();
}
private boolean stopResolveService(int resolveId) {
return mDaemon.execute("stop-resolve", resolveId);
}
- private boolean getAddrInfo(int resolveId, String hostname) {
- return mDaemon.execute("getaddrinfo", resolveId, hostname);
+ private boolean getAddrInfo(int resolveId, String hostname, String interfaceIdx) {
+ // interfaceIdx is always obtained (as string) from the service resolved callback
+ return mDaemon.execute("getaddrinfo", resolveId, hostname, interfaceIdx);
}
private boolean stopGetAddrInfo(int resolveId) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 99e3160fcbe3..df19c67f00e5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -173,8 +173,10 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
public BluetoothDevice getActiveDevice() {
- if (mService == null) return null;
- return mService.getActiveDevice();
+ if (mBluetoothAdapter == null) return null;
+ final List<BluetoothDevice> activeDevices = mBluetoothAdapter
+ .getActiveDevices(BluetoothProfile.A2DP);
+ return (activeDevices.size() > 0) ? activeDevices.get(0) : null;
}
@Override
@@ -221,7 +223,7 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
public boolean supportsHighQualityAudio(BluetoothDevice device) {
- BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
+ BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
if (bluetoothDevice == null) {
return false;
}
@@ -234,7 +236,7 @@ public class A2dpProfile implements LocalBluetoothProfile {
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
- BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
+ BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
if (bluetoothDevice == null) {
return false;
}
@@ -260,7 +262,7 @@ public class A2dpProfile implements LocalBluetoothProfile {
}
public void setHighQualityAudioEnabled(BluetoothDevice device, boolean enabled) {
- BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
+ BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
if (bluetoothDevice == null) {
return;
}
@@ -286,7 +288,7 @@ public class A2dpProfile implements LocalBluetoothProfile {
*/
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
- BluetoothDevice bluetoothDevice = (device != null) ? device : mService.getActiveDevice();
+ BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
if (bluetoothDevice == null || !supportsHighQualityAudio(device)
|| getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index b11bbdec191f..7e5c1240cc63 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -132,10 +132,12 @@ public class HeadsetProfile implements LocalBluetoothProfile {
}
public BluetoothDevice getActiveDevice() {
- if (mService == null) {
+ if (mBluetoothAdapter == null) {
return null;
}
- return mService.getActiveDevice();
+ final List<BluetoothDevice> activeDevices = mBluetoothAdapter
+ .getActiveDevices(BluetoothProfile.HEADSET);
+ return (activeDevices.size() > 0) ? activeDevices.get(0) : null;
}
public int getAudioState(BluetoothDevice device) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index dc109cac37b2..6f2d4decf033 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -173,8 +173,10 @@ public class HearingAidProfile implements LocalBluetoothProfile {
}
public List<BluetoothDevice> getActiveDevices() {
- if (mService == null) return new ArrayList<>();
- return mService.getActiveDevices();
+ if (mBluetoothAdapter == null) {
+ return new ArrayList<>();
+ }
+ return mBluetoothAdapter.getActiveDevices(BluetoothProfile.HEARING_AID);
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
index 209507ac7088..e203cbaa3da5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LeAudioProfile.java
@@ -21,12 +21,12 @@ import static android.bluetooth.BluetoothAdapter.ACTIVE_DEVICE_ALL;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_ALLOWED;
import static android.bluetooth.BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
-import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothCodecConfig;
import android.bluetooth.BluetoothCodecStatus;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAudio;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothUuid;
import android.content.Context;
@@ -144,20 +144,20 @@ public class LeAudioProfile implements LocalBluetoothProfile {
* @hide
*/
public boolean connect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.connect(device);
+ if (mService == null) {
+ return false;
+ }
+ return mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_ALLOWED);
}
/*
* @hide
*/
public boolean disconnect(BluetoothDevice device) {
- if (mService == null) {
- return false;
- }
- return mService.disconnect(device);
+ if (mService == null) {
+ return false;
+ }
+ return mService.setConnectionPolicy(device, BluetoothProfile.CONNECTION_POLICY_FORBIDDEN);
}
public int getConnectionStatus(BluetoothDevice device) {
@@ -177,10 +177,10 @@ public class LeAudioProfile implements LocalBluetoothProfile {
}
public List<BluetoothDevice> getActiveDevices() {
- if (mService == null) {
+ if (mBluetoothAdapter == null) {
return new ArrayList<>();
}
- return mService.getActiveDevices();
+ return mBluetoothAdapter.getActiveDevices(BluetoothProfile.LE_AUDIO);
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index a000c099347d..d179b828d4ab 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -528,7 +528,18 @@ public class DreamBackend {
if (flattenedString.indexOf('/') < 0) {
flattenedString = serviceInfo.packageName + "/" + flattenedString;
}
- return ComponentName.unflattenFromString(flattenedString);
+
+ ComponentName cn = ComponentName.unflattenFromString(flattenedString);
+
+ if (cn == null) return null;
+ if (!cn.getPackageName().equals(serviceInfo.packageName)) {
+ Log.w(TAG,
+ "Inconsistent package name in component: " + cn.getPackageName()
+ + ", should be: " + serviceInfo.packageName);
+ return null;
+ }
+
+ return cn;
}
private static DreamMetadata getDreamMetadata(PackageManager pm, ResolveInfo resolveInfo) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
index f167721f94bf..d7b366e60a1d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/A2dpProfileTest.java
@@ -60,6 +60,8 @@ public class A2dpProfileTest {
private BluetoothDevice mDevice;
@Mock
private BluetoothA2dp mBluetoothA2dp;
+ @Mock
+ private BluetoothAdapter mBluetoothAdapter;
private BluetoothProfile.ServiceListener mServiceListener;
private A2dpProfile mProfile;
@@ -72,7 +74,8 @@ public class A2dpProfileTest {
mProfile = new A2dpProfile(mContext, mDeviceManager, mProfileManager);
mServiceListener = mShadowBluetoothAdapter.getServiceListener();
mServiceListener.onServiceConnected(BluetoothProfile.A2DP, mBluetoothA2dp);
- when(mBluetoothA2dp.getActiveDevice()).thenReturn(mDevice);
+ when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.A2DP)))
+ .thenReturn(Arrays.asList(mDevice));
}
@Test
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ca90fbedd4e0..6f4cd4a0f6ee 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -533,6 +533,7 @@
<!-- Permission needed for CTS test - WifiManagerTest -->
<uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
<uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
+ <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
<uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" />
<!-- Permission required for CTS tests to enable/disable rate limiting toasts. -->
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 08d217d15a5a..4540b77d0a40 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -301,6 +301,7 @@ class ActivityLaunchAnimator(
* The intent was started. If [willAnimate] is false, nothing else will happen and the
* animation will not be started.
*/
+ @JvmDefault
fun onIntentStarted(willAnimate: Boolean) {}
/**
@@ -308,6 +309,7 @@ class ActivityLaunchAnimator(
* this if the animation was already started, i.e. if [onLaunchAnimationStart] was called
* before the cancellation.
*/
+ @JvmDefault
fun onLaunchAnimationCancelled() {}
}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index f7a7603944f6..3051d8056a89 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -19,6 +19,7 @@ package com.android.systemui.animation
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
+import android.app.ActivityManager
import android.app.Dialog
import android.graphics.Color
import android.graphics.Rect
@@ -45,7 +46,8 @@ private const val TAG = "DialogLaunchAnimator"
class DialogLaunchAnimator @JvmOverloads constructor(
private val dreamManager: IDreamManager,
private val launchAnimator: LaunchAnimator = LaunchAnimator(TIMINGS, INTERPOLATORS),
- private var isForTesting: Boolean = false
+ // TODO(b/217621394): Remove special handling for low-RAM devices after animation sync is fixed
+ private var forceDisableSynchronization: Boolean = ActivityManager.isLowRamDeviceStatic()
) {
private companion object {
private val TIMINGS = ActivityLaunchAnimator.TIMINGS
@@ -111,7 +113,7 @@ class DialogLaunchAnimator @JvmOverloads constructor(
dialog = dialog,
animateBackgroundBoundsChange,
animatedParent,
- isForTesting
+ forceDisableSynchronization
)
openedDialogs.add(animatedDialog)
@@ -187,10 +189,9 @@ private class AnimatedDialog(
private val parentAnimatedDialog: AnimatedDialog? = null,
/**
- * Whether we are currently running in a test, in which case we need to disable
- * synchronization.
+ * Whether synchronization should be disabled, which can be useful if we are running in a test.
*/
- private val isForTesting: Boolean
+ private val forceDisableSynchronization: Boolean
) {
/**
* The DecorView of this dialog window.
@@ -420,8 +421,9 @@ private class AnimatedDialog(
* (or inversely, removed from the UI when the touch surface is made visible).
*/
private fun synchronizeNextDraw(then: () -> Unit) {
- if (isForTesting || !touchSurface.isAttachedToWindow || touchSurface.viewRootImpl == null ||
- !decorView.isAttachedToWindow || decorView.viewRootImpl == null) {
+ if (forceDisableSynchronization ||
+ !touchSurface.isAttachedToWindow || touchSurface.viewRootImpl == null ||
+ !decorView.isAttachedToWindow || decorView.viewRootImpl == null) {
// No need to synchronize if either the touch surface or dialog view is not attached
// to a window.
then()
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
index ebe96ebf2988..77386cf2ff10 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/LaunchAnimator.kt
@@ -100,9 +100,11 @@ class LaunchAnimator(
* needed for the animation. [isExpandingFullyAbove] will be true if the window is expanding
* fully above the [launchContainer].
*/
+ @JvmDefault
fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {}
/** The animation made progress and the expandable view [state] should be updated. */
+ @JvmDefault
fun onLaunchAnimationProgress(state: State, progress: Float, linearProgress: Float) {}
/**
@@ -110,6 +112,7 @@ class LaunchAnimator(
* called previously. This is typically used to clean up the resources initialized when the
* animation was started.
*/
+ @JvmDefault
fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) {}
}
diff --git a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
index 29221aa04699..208825ccc8cf 100644
--- a/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
+++ b/packages/SystemUI/monet/src/com/android/systemui/monet/ColorScheme.kt
@@ -103,6 +103,20 @@ enum class Style(internal val coreSpec: CoreSpec) {
n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 32.0))
)),
+ RAINBOW(CoreSpec(
+ a1 = TonalSpec(chroma = Chroma(ChromaStrategy.GTE, 48.0)),
+ a2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0)),
+ a3 = TonalSpec(Hue(HueStrategy.ADD, 60.0), Chroma(ChromaStrategy.EQ, 24.0)),
+ n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 0.0)),
+ n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 0.0))
+ )),
+ FRUIT_SALAD(CoreSpec(
+ a1 = TonalSpec(Hue(HueStrategy.SUBTRACT, 50.0), Chroma(ChromaStrategy.GTE, 48.0)),
+ a2 = TonalSpec(Hue(HueStrategy.SUBTRACT, 50.0), Chroma(ChromaStrategy.EQ, 36.0)),
+ a3 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 36.0)),
+ n1 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 10.0)),
+ n2 = TonalSpec(chroma = Chroma(ChromaStrategy.EQ, 16.0))
+ )),
}
class ColorScheme(
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 4817d453ba0b..c58c00114262 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -14,126 +14,137 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<com.android.systemui.clipboardoverlay.DraggableConstraintLayout
+<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
- android:theme="@style/FloatingOverlay"
android:alpha="0"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
- android:id="@+id/actions_container_background"
- android:visibility="gone"
- android:layout_height="0dp"
- android:layout_width="0dp"
- android:elevation="1dp"
- android:background="@drawable/action_chip_container_background"
- android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
- app:layout_constraintBottom_toBottomOf="@+id/actions_container"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="@+id/actions_container"
- app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
- <HorizontalScrollView
- android:id="@+id/actions_container"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
- android:paddingEnd="@dimen/overlay_action_container_padding_right"
- android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
- android:elevation="1dp"
- android:scrollbars="none"
- app:layout_constraintHorizontal_bias="0"
- app:layout_constraintWidth_percent="1.0"
- app:layout_constraintWidth_max="wrap"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@+id/preview_border"
- app:layout_constraintEnd_toEndOf="parent">
- <LinearLayout
- android:id="@+id/actions"
+ android:id="@+id/background_protection"
+ android:layout_height="@dimen/overlay_bg_protection_height"
+ android:layout_width="match_parent"
+ android:layout_gravity="bottom"
+ android:src="@drawable/overlay_actions_background_protection"/>
+ <com.android.systemui.clipboardoverlay.DraggableConstraintLayout
+ android:id="@+id/clipboard_ui"
+ android:theme="@style/FloatingOverlay"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageView
+ android:id="@+id/actions_container_background"
+ android:visibility="gone"
+ android:layout_height="0dp"
+ android:layout_width="0dp"
+ android:elevation="1dp"
+ android:background="@drawable/action_chip_container_background"
+ android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
+ app:layout_constraintBottom_toBottomOf="@+id/actions_container"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="@+id/actions_container"
+ app:layout_constraintEnd_toEndOf="@+id/actions_container"/>
+ <HorizontalScrollView
+ android:id="@+id/actions_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
+ android:paddingEnd="@dimen/overlay_action_container_padding_right"
+ android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
+ android:elevation="1dp"
+ android:scrollbars="none"
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintWidth_percent="1.0"
+ app:layout_constraintWidth_max="wrap"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/preview_border"
+ app:layout_constraintEnd_toEndOf="parent">
+ <LinearLayout
+ android:id="@+id/actions"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:animateLayoutChanges="true">
+ <include layout="@layout/overlay_action_chip"
+ android:id="@+id/remote_copy_chip"/>
+ <include layout="@layout/overlay_action_chip"
+ android:id="@+id/edit_chip"/>
+ </LinearLayout>
+ </HorizontalScrollView>
+ <View
+ android:id="@+id/preview_border"
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:layout_marginStart="@dimen/overlay_offset_x"
+ android:layout_marginBottom="@dimen/overlay_offset_y"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toBottomOf="@id/actions_container_background"
+ android:elevation="@dimen/overlay_preview_elevation"
+ app:layout_constraintEnd_toEndOf="@id/clipboard_preview_end"
+ app:layout_constraintTop_toTopOf="@id/clipboard_preview_top"
+ android:background="@drawable/overlay_border"/>
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/clipboard_preview_end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:animateLayoutChanges="true">
- <include layout="@layout/overlay_action_chip"
- android:id="@+id/remote_copy_chip"/>
- <include layout="@layout/overlay_action_chip"
- android:id="@+id/edit_chip"/>
- </LinearLayout>
- </HorizontalScrollView>
- <View
- android:id="@+id/preview_border"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:layout_marginStart="@dimen/overlay_offset_x"
- android:layout_marginBottom="@dimen/overlay_offset_y"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toBottomOf="@id/actions_container_background"
- android:elevation="@dimen/overlay_preview_elevation"
- app:layout_constraintEnd_toEndOf="@id/clipboard_preview_end"
- app:layout_constraintTop_toTopOf="@id/clipboard_preview_top"
- android:background="@drawable/overlay_border"/>
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/clipboard_preview_end"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierMargin="@dimen/overlay_border_width"
- app:barrierDirection="end"
- app:constraint_referenced_ids="clipboard_preview"/>
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/clipboard_preview_top"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:barrierDirection="top"
- app:barrierMargin="@dimen/overlay_border_width_neg"
- app:constraint_referenced_ids="clipboard_preview"/>
- <FrameLayout
- android:id="@+id/clipboard_preview"
- android:elevation="@dimen/overlay_preview_elevation"
- android:background="@drawable/overlay_preview_background"
- android:clipChildren="true"
- android:clipToOutline="true"
- android:clipToPadding="true"
- android:layout_width="@dimen/clipboard_preview_size"
- android:layout_margin="@dimen/overlay_border_width"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- app:layout_constraintBottom_toBottomOf="@id/preview_border"
- app:layout_constraintStart_toStartOf="@id/preview_border"
- app:layout_constraintEnd_toEndOf="@id/preview_border"
- app:layout_constraintTop_toTopOf="@id/preview_border">
- <TextView android:id="@+id/text_preview"
- android:textFontWeight="500"
- android:padding="8dp"
- android:gravity="center|start"
- android:ellipsize="end"
- android:autoSizeTextType="uniform"
- android:autoSizeMinTextSize="10sp"
- android:autoSizeMaxTextSize="200sp"
- android:textColor="?android:attr/textColorPrimary"
- android:layout_width="@dimen/clipboard_preview_size"
- android:layout_height="@dimen/clipboard_preview_size"/>
- <ImageView
- android:id="@+id/image_preview"
- android:scaleType="fitCenter"
- android:adjustViewBounds="true"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- </FrameLayout>
- <FrameLayout
- android:id="@+id/dismiss_button"
- android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
- android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
- android:elevation="@dimen/overlay_dismiss_button_elevation"
- android:visibility="gone"
- app:layout_constraintStart_toEndOf="@id/clipboard_preview"
- app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
- app:layout_constraintTop_toTopOf="@id/clipboard_preview"
- app:layout_constraintBottom_toTopOf="@id/clipboard_preview"
- android:contentDescription="@string/clipboard_dismiss_description">
- <ImageView
- android:id="@+id/dismiss_image"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_margin="@dimen/overlay_dismiss_button_margin"
- android:src="@drawable/overlay_cancel"/>
- </FrameLayout>
-</com.android.systemui.clipboardoverlay.DraggableConstraintLayout>
+ app:barrierMargin="@dimen/overlay_border_width"
+ app:barrierDirection="end"
+ app:constraint_referenced_ids="clipboard_preview"/>
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/clipboard_preview_top"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:barrierDirection="top"
+ app:barrierMargin="@dimen/overlay_border_width_neg"
+ app:constraint_referenced_ids="clipboard_preview"/>
+ <FrameLayout
+ android:id="@+id/clipboard_preview"
+ android:elevation="@dimen/overlay_preview_elevation"
+ android:background="@drawable/overlay_preview_background"
+ android:clipChildren="true"
+ android:clipToOutline="true"
+ android:clipToPadding="true"
+ android:layout_width="@dimen/clipboard_preview_size"
+ android:layout_margin="@dimen/overlay_border_width"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ app:layout_constraintBottom_toBottomOf="@id/preview_border"
+ app:layout_constraintStart_toStartOf="@id/preview_border"
+ app:layout_constraintEnd_toEndOf="@id/preview_border"
+ app:layout_constraintTop_toTopOf="@id/preview_border">
+ <TextView android:id="@+id/text_preview"
+ android:textFontWeight="500"
+ android:padding="8dp"
+ android:gravity="center|start"
+ android:ellipsize="end"
+ android:autoSizeTextType="uniform"
+ android:autoSizeMinTextSize="10sp"
+ android:autoSizeMaxTextSize="200sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:layout_width="@dimen/clipboard_preview_size"
+ android:layout_height="@dimen/clipboard_preview_size"/>
+ <ImageView
+ android:id="@+id/image_preview"
+ android:scaleType="fitCenter"
+ android:adjustViewBounds="true"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </FrameLayout>
+ <FrameLayout
+ android:id="@+id/dismiss_button"
+ android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
+ android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
+ android:elevation="@dimen/overlay_dismiss_button_elevation"
+ android:visibility="gone"
+ app:layout_constraintStart_toEndOf="@id/clipboard_preview"
+ app:layout_constraintEnd_toEndOf="@id/clipboard_preview"
+ app:layout_constraintTop_toTopOf="@id/clipboard_preview"
+ app:layout_constraintBottom_toTopOf="@id/clipboard_preview"
+ android:contentDescription="@string/clipboard_dismiss_description">
+ <ImageView
+ android:id="@+id/dismiss_image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="@dimen/overlay_dismiss_button_margin"
+ android:src="@drawable/overlay_cancel"/>
+ </FrameLayout>
+ </com.android.systemui.clipboardoverlay.DraggableConstraintLayout>
+</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
index a41d34f8ab41..82c8d5f04327 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
@@ -20,7 +20,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/dream_overlay_complication_clock_time_padding_left"
- android:fontFamily="sans-serif-thin"
+ android:fontFamily="@font/clock"
android:textColor="@android:color/white"
android:format12Hour="h:mm"
android:format24Hour="kk:mm"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4dca0b0076d9..e5cabb0ecac0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2379,11 +2379,15 @@
<string name="fgs_manager_dialog_title">Active apps</string>
<!-- Label of the button to stop an app from running [CHAR LIMIT=12]-->
<string name="fgs_manager_app_item_stop_button_label">Stop</string>
+ <!-- Label of the button to stop an app from running but the app is already stopped and the button is disabled [CHAR LIMIT=12]-->
+ <string name="fgs_manager_app_item_stop_button_stopped_label">Stopped</string>
<!-- Label for button to copy edited text back to the clipboard [CHAR LIMIT=20] -->
<string name="clipboard_edit_text_copy">Copy</string>
<!-- Text informing user that content has been copied to the system clipboard [CHAR LIMIT=NONE] -->
<string name="clipboard_overlay_text_copied">Copied</string>
+ <!-- Text informing user where text being edited was copied from [CHAR LIMIT=NONE] -->
+ <string name="clipboard_edit_source">From <xliff:g id="appName" example="Gmail">%1$s</xliff:g></string>
<!-- Label for button to dismiss clipboard overlay [CHAR LIMIT=NONE] -->
<string name="clipboard_dismiss_description">Dismiss copy UI</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index cc10b02a8bb6..d7a8a7aa2c10 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -680,6 +680,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
/**
+ * Whether the secure camera is currently showing over the keyguard.
+ */
+ public boolean isSecureCameraLaunchedOverKeyguard() {
+ return mSecureCameraLaunched;
+ }
+
+ /**
* @return a cached version of DreamManager.isDreaming()
*/
public boolean isDreaming() {
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
index 72b40d42b7b8..54664f2fdd93 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
@@ -48,7 +48,7 @@ public class ClipboardListener extends CoreStartable
@Override
public void start() {
if (DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, false)) {
+ DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_ENABLED, true)) {
mClipboardManager = requireNonNull(mContext.getSystemService(ClipboardManager.class));
mClipboardManager.addPrimaryClipChangedListener(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index 8b549b43019f..f6d64643b3cd 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -103,6 +103,7 @@ public class ClipboardOverlayController {
private final AccessibilityManager mAccessibilityManager;
private final TextClassifier mTextClassifier;
+ private final FrameLayout mContainer;
private final DraggableConstraintLayout mView;
private final ImageView mImagePreview;
private final TextView mTextPreview;
@@ -147,8 +148,9 @@ public class ClipboardOverlayController {
mWindow = FloatingWindowUtil.getFloatingWindow(mContext);
mWindow.setWindowManager(mWindowManager, null, null);
- mView = (DraggableConstraintLayout)
+ mContainer = (FrameLayout)
LayoutInflater.from(mContext).inflate(R.layout.clipboard_overlay, null);
+ mView = requireNonNull(mContainer.findViewById(R.id.clipboard_ui));
mActionContainerBackground =
requireNonNull(mView.findViewById(R.id.actions_container_background));
mActionContainer = requireNonNull(mView.findViewById(R.id.actions));
@@ -180,7 +182,7 @@ public class ClipboardOverlayController {
attachWindow();
withWindowAttached(() -> {
- mWindow.setContentView(mView);
+ mWindow.setContentView(mContainer);
updateInsets(mWindowManager.getCurrentWindowMetrics().getWindowInsets());
mView.requestLayout();
mView.post(this::animateIn);
@@ -371,7 +373,7 @@ public class ClipboardOverlayController {
private ValueAnimator getEnterAnimation() {
ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
- mView.setAlpha(0);
+ mContainer.setAlpha(0);
mDismissButton.setVisibility(View.GONE);
final View previewBorder = requireNonNull(mView.findViewById(R.id.preview_border));
final View actionBackground = requireNonNull(
@@ -383,7 +385,7 @@ public class ClipboardOverlayController {
}
anim.addUpdateListener(animation -> {
- mView.setAlpha(animation.getAnimatedFraction());
+ mContainer.setAlpha(animation.getAnimatedFraction());
float scale = 0.6f + 0.4f * animation.getAnimatedFraction();
mView.setPivotY(mView.getHeight() - previewBorder.getHeight() / 2f);
mView.setPivotX(actionBackground.getWidth() / 2f);
@@ -394,7 +396,7 @@ public class ClipboardOverlayController {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- mView.setAlpha(1);
+ mContainer.setAlpha(1);
mTimeoutHandler.resetTimeout();
}
});
@@ -439,7 +441,7 @@ public class ClipboardOverlayController {
private void reset() {
mView.setTranslationX(0);
- mView.setAlpha(0);
+ mContainer.setAlpha(0);
resetActionChips();
mTimeoutHandler.cancelTimeout();
}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
index be10c359f3c1..a57a1351779f 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/EditTextActivity.java
@@ -22,9 +22,12 @@ import android.app.Activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Bundle;
+import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
+import android.widget.TextView;
import com.android.systemui.R;
@@ -32,8 +35,11 @@ import com.android.systemui.R;
* Lightweight activity for editing text clipboard contents
*/
public class EditTextActivity extends Activity {
+ private static final String TAG = "EditTextActivity";
+
private EditText mEditText;
private ClipboardManager mClipboardManager;
+ private TextView mAttribution;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -42,6 +48,7 @@ public class EditTextActivity extends Activity {
findViewById(R.id.copy_button).setOnClickListener((v) -> saveToClipboard());
findViewById(R.id.share).setOnClickListener((v) -> share());
mEditText = findViewById(R.id.edit_text);
+ mAttribution = findViewById(R.id.attribution);
mClipboardManager = requireNonNull(getSystemService(ClipboardManager.class));
}
@@ -53,7 +60,15 @@ public class EditTextActivity extends Activity {
finish();
return;
}
- // TODO: put clip attribution in R.id.attribution TextView
+ PackageManager pm = getApplicationContext().getPackageManager();
+ try {
+ CharSequence label = pm.getApplicationLabel(
+ pm.getApplicationInfo(mClipboardManager.getPrimaryClipSource(),
+ PackageManager.ApplicationInfoFlags.of(0)));
+ mAttribution.setText(getResources().getString(R.string.clipboard_edit_source, label));
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Package not found: " + mClipboardManager.getPrimaryClipSource(), e);
+ }
mEditText.setText(clip.getItemAt(0).getText());
mEditText.requestFocus();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 2160744c6803..77997e437e33 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -31,8 +31,10 @@ import androidx.lifecycle.ViewModelStore;
import com.android.internal.policy.PhoneWindow;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.complication.Complication;
+import com.android.systemui.dreams.complication.ComplicationUtils;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor;
@@ -57,6 +59,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
// content area).
private final DreamOverlayContainerViewController mDreamOverlayContainerViewController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final DreamBackend mDreamBackend;
// A reference to the {@link Window} used to hold the dream overlay.
private Window mWindow;
@@ -109,6 +112,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
setCurrentState(Lifecycle.State.CREATED);
mLifecycleRegistry = component.getLifecycleRegistry();
mDreamOverlayTouchMonitor = component.getDreamOverlayTouchMonitor();
+ mDreamBackend = component.getDreamBackend();
mDreamOverlayTouchMonitor.init();
}
@@ -130,6 +134,9 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
setCurrentState(Lifecycle.State.STARTED);
mExecutor.execute(() -> {
+ mStateController.setAvailableComplicationTypes(
+ ComplicationUtils.convertComplicationTypes(
+ mDreamBackend.getEnabledComplications()));
addOverlayWindowLocked(layoutParams);
setCurrentState(Lifecycle.State.RESUMED);
mStateController.setOverlayActive(true);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
index ac7457d90e49..bc5a52a40a35 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayStateController.java
@@ -131,9 +131,7 @@ public class DreamOverlayStateController implements
.filter(complication -> {
@Complication.ComplicationType
final int requiredTypes = complication.getRequiredTypeAvailability();
-
- return requiredTypes == Complication.COMPLICATION_TYPE_NONE
- || (requiredTypes & getAvailableComplicationTypes()) == requiredTypes;
+ return (requiredTypes & getAvailableComplicationTypes()) == requiredTypes;
})
.collect(Collectors.toCollection(HashSet::new))
: mComplications);
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java
index 3a2a6ef60f03..a4a0075e742a 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationUtils.java
@@ -25,6 +25,8 @@ import static com.android.systemui.dreams.complication.Complication.COMPLICATION
import com.android.settingslib.dream.DreamBackend;
+import java.util.Set;
+
/**
* A collection of utility methods for working with {@link Complication}.
*/
@@ -50,4 +52,14 @@ public class ComplicationUtils {
return COMPLICATION_TYPE_NONE;
}
}
+
+ /**
+ * Converts a set of {@link com.android.settingslib.dream.DreamBackend.ComplicationType} to
+ * a combined complications types state.
+ */
+ @Complication.ComplicationType
+ public static int convertComplicationTypes(@DreamBackend.ComplicationType Set<Integer> types) {
+ return types.stream().mapToInt(ComplicationUtils::convertComplicationType).reduce(
+ COMPLICATION_TYPE_NONE, (a, b) -> a | b);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
index 59c52b9e402b..6861c7479161 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockDateComplication.java
@@ -44,6 +44,11 @@ public class DreamClockDateComplication implements Complication {
mComponentFactory = componentFactory;
}
+ @Override
+ public int getRequiredTypeAvailability() {
+ return COMPLICATION_TYPE_DATE;
+ }
+
/**
* Create {@link DreamClockDateViewHolder}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
index b0c3a424cc92..936767a60233 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamClockTimeComplication.java
@@ -44,6 +44,11 @@ public class DreamClockTimeComplication implements Complication {
mComponentFactory = componentFactory;
}
+ @Override
+ public int getRequiredTypeAvailability() {
+ return COMPLICATION_TYPE_TIME;
+ }
+
/**
* Create {@link DreamClockTimeViewHolder}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
index cbdbef3ae57e..f5c5a434a077 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamWeatherComplication.java
@@ -53,6 +53,11 @@ public class DreamWeatherComplication implements Complication {
mComponentFactory = componentFactory;
}
+ @Override
+ public int getRequiredTypeAvailability() {
+ return COMPLICATION_TYPE_WEATHER;
+ }
+
/**
* Create {@link DreamWeatherViewHolder}.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
index 053c5b345760..d539f5c2b870 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationComponent.java
@@ -22,6 +22,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.TextClock;
import com.android.internal.util.Preconditions;
import com.android.systemui.R;
@@ -78,6 +79,8 @@ public interface DreamClockTimeComplicationComponent {
"clock_time_complication_layout_params";
// Order weight of insert into parent container
int INSERT_ORDER_WEIGHT = 0;
+ String TAG_WEIGHT = "'wght' ";
+ int WEIGHT = 200;
/**
* Provides the complication view.
@@ -86,10 +89,12 @@ public interface DreamClockTimeComplicationComponent {
@DreamClockTimeComplicationScope
@Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
static View provideComplicationView(LayoutInflater layoutInflater) {
- return Preconditions.checkNotNull(
- layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
- null, false),
+ final TextClock view = Preconditions.checkNotNull((TextClock)
+ layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
+ null, false),
"R.layout.dream_overlay_complication_clock_time did not properly inflated");
+ view.setFontVariationSettings(TAG_WEIGHT + WEIGHT);
+ return view;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
index 05ab9015fecc..60278a9da7eb 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayComponent.java
@@ -22,6 +22,7 @@ import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.lifecycle.ViewModelStore;
+import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.dreams.DreamOverlayContainerViewController;
import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.dreams.complication.dagger.ComplicationModule;
@@ -68,4 +69,7 @@ public interface DreamOverlayComponent {
/** Builds a {@link DreamOverlayTouchMonitor} */
DreamOverlayTouchMonitor getDreamOverlayTouchMonitor();
+
+ /** Builds a ${@link DreamBackend} */
+ DreamBackend getDreamBackend();
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index 4eb5cb97607a..efa063f4dfc8 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -17,6 +17,7 @@
package com.android.systemui.dreams.dagger;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
import android.view.LayoutInflater;
@@ -27,6 +28,7 @@ import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import com.android.internal.util.Preconditions;
+import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.R;
import com.android.systemui.battery.BatteryMeterView;
import com.android.systemui.battery.BatteryMeterViewController;
@@ -147,4 +149,10 @@ public abstract class DreamOverlayModule {
static Lifecycle providesLifecycle(LifecycleOwner lifecycleOwner) {
return lifecycleOwner.getLifecycle();
}
+
+ @Provides
+ @DreamOverlayComponent.DreamOverlayScope
+ static DreamBackend providesDreamBackend(Context context) {
+ return DreamBackend.getInstance(context);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialog.kt b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialog.kt
deleted file mode 100644
index 42f3512129a3..000000000000
--- a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialog.kt
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.fgsmanager
-
-import android.content.Context
-import android.os.Bundle
-import android.text.format.DateUtils
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.Button
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.annotation.GuardedBy
-import androidx.recyclerview.widget.DiffUtil
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import com.android.systemui.R
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.fgsmanager.FgsManagerDialogController.RunningApp
-import com.android.systemui.statusbar.phone.SystemUIDialog
-import com.android.systemui.util.time.SystemClock
-import java.util.concurrent.Executor
-
-/**
- * Dialog which shows a list of running foreground services and offers controls to them
- */
-class FgsManagerDialog(
- context: Context,
- private val executor: Executor,
- @Background private val backgroundExecutor: Executor,
- private val systemClock: SystemClock,
- private val fgsManagerDialogController: FgsManagerDialogController
-) : SystemUIDialog(context, R.style.Theme_SystemUI_Dialog) {
-
- private val appListRecyclerView: RecyclerView = RecyclerView(this.context)
- private val adapter: AppListAdapter = AppListAdapter()
-
- init {
- setTitle(R.string.fgs_manager_dialog_title)
- setView(appListRecyclerView)
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- appListRecyclerView.layoutManager = LinearLayoutManager(context)
- fgsManagerDialogController.registerDialogForChanges(
- object : FgsManagerDialogController.FgsManagerDialogCallback {
- override fun onRunningAppsChanged(apps: List<RunningApp>) {
- executor.execute {
- adapter.setData(apps)
- }
- }
- }
- )
- appListRecyclerView.adapter = adapter
- backgroundExecutor.execute { adapter.setData(fgsManagerDialogController.runningAppList) }
- }
-
- private inner class AppListAdapter : RecyclerView.Adapter<AppItemViewHolder>() {
- private val lock = Any()
-
- @GuardedBy("lock")
- private val data: MutableList<RunningApp> = ArrayList()
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppItemViewHolder {
- return AppItemViewHolder(LayoutInflater.from(context)
- .inflate(R.layout.fgs_manager_app_item, parent, false))
- }
-
- override fun onBindViewHolder(holder: AppItemViewHolder, position: Int) {
- var runningApp: RunningApp
- synchronized(lock) {
- runningApp = data[position]
- }
- with(holder) {
- iconView.setImageDrawable(runningApp.mIcon)
- appLabelView.text = runningApp.mAppLabel
- durationView.text = DateUtils.formatDuration(
- Math.max(systemClock.elapsedRealtime() - runningApp.mTimeStarted, 60000),
- DateUtils.LENGTH_MEDIUM)
- stopButton.setOnClickListener {
- fgsManagerDialogController
- .stopAllFgs(runningApp.mUserId, runningApp.mPackageName)
- }
- }
- }
-
- override fun getItemCount(): Int {
- synchronized(lock) { return data.size }
- }
-
- fun setData(newData: List<RunningApp>) {
- var oldData: List<RunningApp>
- synchronized(lock) {
- oldData = ArrayList(data)
- data.clear()
- data.addAll(newData)
- }
-
- DiffUtil.calculateDiff(object : DiffUtil.Callback() {
- override fun getOldListSize(): Int {
- return oldData.size
- }
-
- override fun getNewListSize(): Int {
- return newData.size
- }
-
- override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int):
- Boolean {
- return oldData[oldItemPosition] == newData[newItemPosition]
- }
-
- override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int):
- Boolean {
- return true // TODO, look into updating the time subtext
- }
- }).dispatchUpdatesTo(this)
- }
- }
-
- private class AppItemViewHolder(parent: View) : RecyclerView.ViewHolder(parent) {
- val appLabelView: TextView = parent.requireViewById(R.id.fgs_manager_app_item_label)
- val durationView: TextView = parent.requireViewById(R.id.fgs_manager_app_item_duration)
- val iconView: ImageView = parent.requireViewById(R.id.fgs_manager_app_item_icon)
- val stopButton: Button = parent.requireViewById(R.id.fgs_manager_app_item_stop_button)
- }
-} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogController.kt b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogController.kt
deleted file mode 100644
index 159ed39025a1..000000000000
--- a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogController.kt
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.fgsmanager
-
-import android.content.pm.PackageManager
-import android.content.pm.PackageManager.NameNotFoundException
-import android.graphics.drawable.Drawable
-import android.os.Handler
-import android.os.UserHandle
-import android.util.ArrayMap
-import android.util.Log
-import androidx.annotation.GuardedBy
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.statusbar.policy.RunningFgsController
-import com.android.systemui.statusbar.policy.RunningFgsController.UserPackageTime
-import javax.inject.Inject
-
-/**
- * Controls events relevant to FgsManagerDialog
- */
-class FgsManagerDialogController @Inject constructor(
- private val packageManager: PackageManager,
- @Background private val backgroundHandler: Handler,
- private val runningFgsController: RunningFgsController
-) : RunningFgsController.Callback {
- private val lock = Any()
- private val clearCacheToken = Any()
-
- @GuardedBy("lock")
- private var runningApps: Map<UserPackageTime, RunningApp>? = null
- @GuardedBy("lock")
- private var listener: FgsManagerDialogCallback? = null
-
- interface FgsManagerDialogCallback {
- fun onRunningAppsChanged(apps: List<RunningApp>)
- }
-
- data class RunningApp(
- val mUserId: Int,
- val mPackageName: String,
- val mAppLabel: CharSequence,
- val mIcon: Drawable,
- val mTimeStarted: Long
- )
-
- val runningAppList: List<RunningApp>
- get() {
- synchronized(lock) {
- if (runningApps == null) {
- onFgsPackagesChangedLocked(runningFgsController.getPackagesWithFgs())
- }
- return convertToRunningAppList(runningApps!!)
- }
- }
-
- fun registerDialogForChanges(callback: FgsManagerDialogCallback) {
- synchronized(lock) {
- runningFgsController.addCallback(this)
- listener = callback
- backgroundHandler.removeCallbacksAndMessages(clearCacheToken)
- }
- }
-
- fun onFinishDialog() {
- synchronized(lock) {
- listener = null
- // Keep data such as icons cached for some time since loading can be slow
- backgroundHandler.postDelayed(
- {
- synchronized(lock) {
- runningFgsController.removeCallback(this)
- runningApps = null
- }
- }, clearCacheToken, RUNNING_APP_CACHE_TIMEOUT_MILLIS)
- }
- }
-
- private fun onRunningAppsChanged(apps: ArrayMap<UserPackageTime, RunningApp>) {
- listener?.let {
- backgroundHandler.post { it.onRunningAppsChanged(convertToRunningAppList(apps)) }
- }
- }
-
- override fun onFgsPackagesChanged(packages: List<UserPackageTime>) {
- backgroundHandler.post {
- synchronized(lock) { onFgsPackagesChangedLocked(packages) }
- }
- }
-
- /**
- * Run on background thread
- */
- private fun onFgsPackagesChangedLocked(packages: List<UserPackageTime>) {
- val newRunningApps = ArrayMap<UserPackageTime, RunningApp>()
- for (packageWithFgs in packages) {
- val ra = runningApps?.get(packageWithFgs)
- if (ra == null) {
- val userId = packageWithFgs.userId
- val packageName = packageWithFgs.packageName
- try {
- val ai = packageManager.getApplicationInfo(packageName, 0)
- var icon = packageManager.getApplicationIcon(ai)
- icon = packageManager.getUserBadgedIcon(icon,
- UserHandle.of(userId))
- val label = packageManager.getApplicationLabel(ai)
- newRunningApps[packageWithFgs] = RunningApp(userId, packageName,
- label, icon, packageWithFgs.startTimeMillis)
- } catch (e: NameNotFoundException) {
- Log.e(LOG_TAG,
- "Application info not found: $packageName", e)
- }
- } else {
- newRunningApps[packageWithFgs] = ra
- }
- }
- runningApps = newRunningApps
- onRunningAppsChanged(newRunningApps)
- }
-
- fun stopAllFgs(userId: Int, packageName: String) {
- runningFgsController.stopFgs(userId, packageName)
- }
-
- companion object {
- private val LOG_TAG = FgsManagerDialogController::class.java.simpleName
- private const val RUNNING_APP_CACHE_TIMEOUT_MILLIS: Long = 20_000
-
- private fun convertToRunningAppList(apps: Map<UserPackageTime, RunningApp>):
- List<RunningApp> {
- val result = mutableListOf<RunningApp>()
- result.addAll(apps.values)
- result.sortWith { a: RunningApp, b: RunningApp ->
- b.mTimeStarted.compareTo(a.mTimeStarted)
- }
- return result
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogFactory.kt
deleted file mode 100644
index 28749296c4cf..000000000000
--- a/packages/SystemUI/src/com/android/systemui/fgsmanager/FgsManagerDialogFactory.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.fgsmanager
-
-import android.content.Context
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.animation.DialogLaunchAnimator
-import android.content.DialogInterface
-import android.view.View
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.util.time.SystemClock
-import java.util.concurrent.Executor
-import javax.inject.Inject
-
-/**
- * Factory to create [FgsManagerDialog] instances
- */
-@SysUISingleton
-class FgsManagerDialogFactory
-@Inject constructor(
- private val context: Context,
- @Main private val executor: Executor,
- @Background private val backgroundExecutor: Executor,
- private val systemClock: SystemClock,
- private val dialogLaunchAnimator: DialogLaunchAnimator,
- private val fgsManagerDialogController: FgsManagerDialogController
-) {
-
- val lock = Any()
-
- companion object {
- private var fgsManagerDialog: FgsManagerDialog? = null
- }
-
- /**
- * Creates the dialog if it doesn't exist
- */
- fun create(viewLaunchedFrom: View?) {
- if (fgsManagerDialog == null) {
- fgsManagerDialog = FgsManagerDialog(context, executor, backgroundExecutor,
- systemClock, fgsManagerDialogController)
- fgsManagerDialog!!.setOnDismissListener { i: DialogInterface? ->
- fgsManagerDialogController.onFinishDialog()
- fgsManagerDialog = null
- }
- dialogLaunchAnimator.showFromView(fgsManagerDialog!!, viewLaunchedFrom!!)
- }
- }
-} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
index d1a103e3a8fa..de67ba8a6ded 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java
@@ -40,6 +40,7 @@ public class GlobalActionsPopupMenu extends ListPopupWindow {
private boolean mIsDropDownMode;
private int mMenuVerticalPadding = 0;
private int mGlobalActionsSidePadding = 0;
+ private int mMaximumWidthThresholdDp = 800;
private ListAdapter mAdapter;
private AdapterView.OnItemLongClickListener mOnItemLongClickListener;
@@ -92,6 +93,8 @@ public class GlobalActionsPopupMenu extends ListPopupWindow {
// width should be between [.5, .9] of screen
int parentWidth = res.getSystem().getDisplayMetrics().widthPixels;
+ float parentDensity = res.getSystem().getDisplayMetrics().density;
+ float parentWidthDp = parentWidth / parentDensity;
int widthSpec = MeasureSpec.makeMeasureSpec(
(int) (parentWidth * 0.9), MeasureSpec.AT_MOST);
int maxWidth = 0;
@@ -101,9 +104,12 @@ public class GlobalActionsPopupMenu extends ListPopupWindow {
int w = child.getMeasuredWidth();
maxWidth = Math.max(w, maxWidth);
}
- int width = Math.max(maxWidth, (int) (parentWidth * 0.5));
- listView.setPadding(0, mMenuVerticalPadding, 0, mMenuVerticalPadding);
+ int width = maxWidth;
+ if (parentWidthDp < mMaximumWidthThresholdDp) {
+ width = Math.max(maxWidth, (int) (parentWidth * 0.5));
+ }
+ listView.setPadding(0, mMenuVerticalPadding, 0, mMenuVerticalPadding);
setWidth(width);
if (getAnchorView().getLayoutDirection() == LayoutDirection.LTR) {
setHorizontalOffset(getAnchorView().getWidth() - mGlobalActionsSidePadding - width);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index e88011e0d3fe..88555edd1e8b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -233,10 +233,13 @@ public class KeyguardService extends Service {
mKeyguardViewMediator = keyguardViewMediator;
mKeyguardLifecyclesDispatcher = keyguardLifecyclesDispatcher;
mShellTransitions = shellTransitions;
+ }
- if (shellTransitions != null && Transitions.ENABLE_SHELL_TRANSITIONS) {
- // Nothing here. Initialization for this happens in onCreate.
- } else {
+ @Override
+ public void onCreate() {
+ ((SystemUIApplication) getApplication()).startServicesIfNeeded();
+
+ if (mShellTransitions == null || !Transitions.ENABLE_SHELL_TRANSITIONS) {
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
if (sEnableRemoteKeyguardGoingAwayAnimation) {
final RemoteAnimationAdapter exitAnimationAdapter =
@@ -248,22 +251,19 @@ public class KeyguardService extends Service {
}
if (sEnableRemoteKeyguardOccludeAnimation) {
final RemoteAnimationAdapter occludeAnimationAdapter =
- new RemoteAnimationAdapter(mOccludeAnimationRunner, 0, 0);
+ new RemoteAnimationAdapter(
+ mKeyguardViewMediator.getOccludeAnimationRunner(), 0, 0);
definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE,
occludeAnimationAdapter);
+
+ final RemoteAnimationAdapter unoccludeAnimationAdapter =
+ new RemoteAnimationAdapter(
+ mKeyguardViewMediator.getUnoccludeAnimationRunner(), 0, 0);
definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_UNOCCLUDE,
- occludeAnimationAdapter);
+ unoccludeAnimationAdapter);
}
ActivityTaskManager.getInstance().registerRemoteAnimationsForDisplay(
DEFAULT_DISPLAY, definition);
- }
- }
-
- @Override
- public void onCreate() {
- ((SystemUIApplication) getApplication()).startServicesIfNeeded();
-
- if (mShellTransitions == null || !Transitions.ENABLE_SHELL_TRANSITIONS) {
return;
}
if (sEnableRemoteKeyguardGoingAwayAnimation) {
@@ -354,33 +354,6 @@ public class KeyguardService extends Service {
}
};
- private final IRemoteAnimationRunner.Stub mOccludeAnimationRunner =
- new IRemoteAnimationRunner.Stub() {
- @Override // Binder interface
- public void onAnimationStart(@WindowManager.TransitionOldType int transit,
- RemoteAnimationTarget[] apps,
- RemoteAnimationTarget[] wallpapers,
- RemoteAnimationTarget[] nonApps,
- IRemoteAnimationFinishedCallback finishedCallback) {
- Slog.d(TAG, "mOccludeAnimationRunner.onAnimationStart: transit=" + transit);
- try {
- if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) {
- mBinder.setOccluded(true /* isOccluded */, true /* animate */);
- } else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE) {
- mBinder.setOccluded(false /* isOccluded */, false /* animate */);
- }
- // TODO(bc-unlock): Implement (un)occlude animation.
- finishedCallback.onAnimationFinished();
- } catch (RemoteException e) {
- Slog.e(TAG, "RemoteException");
- }
- }
-
- @Override // Binder interface
- public void onAnimationCancelled() {
- }
- };
-
final IRemoteTransition mOccludeAnimation = new IRemoteTransition.Stub() {
@Override
public void startAnimation(IBinder transition, TransitionInfo info,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index fd2c6dd3ca36..0f08a1863e08 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -77,11 +77,13 @@ import android.view.IRemoteAnimationRunner;
import android.view.RemoteAnimationTarget;
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.View;
+import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.internal.jank.InteractionJankMonitor;
@@ -89,6 +91,7 @@ import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.policy.IKeyguardDismissCallback;
import com.android.internal.policy.IKeyguardExitCallback;
import com.android.internal.policy.IKeyguardStateCallback;
+import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardConstants;
@@ -102,7 +105,10 @@ import com.android.keyguard.mediator.ScreenOnCoordinator;
import com.android.systemui.CoreStartable;
import com.android.systemui.DejankUtils;
import com.android.systemui.Dumpable;
+import com.android.systemui.R;
+import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.Interpolators;
+import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.dagger.qualifiers.UiBackground;
@@ -375,6 +381,9 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
private int mUnlockSoundId;
private int mTrustedSoundId;
private int mLockSoundStreamId;
+ private final float mPowerButtonY;
+ private final float mWindowCornerRadius;
+
/**
* The animation used for hiding keyguard. This is used to fetch the animation timings if
* WindowManager is not providing us with them.
@@ -815,6 +824,109 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
}
};
+ /**
+ * Animation launch controller for activities that occlude the keyguard.
+ */
+ private final ActivityLaunchAnimator.Controller mOccludeAnimationController =
+ new ActivityLaunchAnimator.Controller() {
+ @Override
+ public void onLaunchAnimationStart(boolean isExpandingFullyAbove) {
+ setOccluded(true /* occluded */, false /* animate */);
+ }
+
+ @Override
+ public void onLaunchAnimationCancelled() {
+ setOccluded(true /* occluded */, false /* animate */);
+ }
+
+ @NonNull
+ @Override
+ public ViewGroup getLaunchContainer() {
+ return ((ViewGroup) mKeyguardViewControllerLazy.get()
+ .getViewRootImpl().getView());
+ }
+
+ @Override
+ public void setLaunchContainer(@NonNull ViewGroup launchContainer) {
+ // No-op, launch container is always the shade.
+ Log.wtf(TAG, "Someone tried to change the launch container for the "
+ + "ActivityLaunchAnimator, which should never happen.");
+ }
+
+ @NonNull
+ @Override
+ public LaunchAnimator.State createAnimatorState() {
+ final int width = getLaunchContainer().getWidth();
+ final int height = getLaunchContainer().getHeight();
+
+ final float initialHeight = height / 3f;
+ final float initialWidth = width / 3f;
+
+ if (mUpdateMonitor.isSecureCameraLaunchedOverKeyguard()) {
+ // Start the animation near the power button, at one-third size, since the
+ // camera was launched from the power button.
+ return new LaunchAnimator.State(
+ (int) (mPowerButtonY - initialHeight / 2f) /* top */,
+ (int) (mPowerButtonY + initialHeight / 2f) /* bottom */,
+ (int) (width - initialWidth) /* left */,
+ width /* right */,
+ mWindowCornerRadius, mWindowCornerRadius);
+ } else {
+ // Start the animation in the center of the screen, scaled down.
+ return new LaunchAnimator.State(
+ height / 2, height / 2, width / 2, width / 2,
+ mWindowCornerRadius, mWindowCornerRadius);
+ }
+ }
+ };
+
+ /**
+ * Animation controller for activities that unocclude the keyguard. This will play the launch
+ * animation in reverse.
+ */
+ private final ActivityLaunchAnimator.Controller mUnoccludeAnimationController =
+ new ActivityLaunchAnimator.Controller() {
+ @Override
+ public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) {
+ setOccluded(false /* isOccluded */, false /* animate */);
+ }
+
+ @Override
+ public void onLaunchAnimationCancelled() {
+ setOccluded(false /* isOccluded */, false /* animate */);
+ }
+
+ @NonNull
+ @Override
+ public ViewGroup getLaunchContainer() {
+ return ((ViewGroup) mKeyguardViewControllerLazy.get()
+ .getViewRootImpl().getView());
+ }
+
+ @Override
+ public void setLaunchContainer(@NonNull ViewGroup launchContainer) {
+ // No-op, launch container is always the shade.
+ Log.wtf(TAG, "Someone tried to change the launch container for the "
+ + "ActivityLaunchAnimator, which should never happen.");
+ }
+
+ @NonNull
+ @Override
+ public LaunchAnimator.State createAnimatorState() {
+ final int width = getLaunchContainer().getWidth();
+ final int height = getLaunchContainer().getHeight();
+
+ // TODO(b/207399883): Unocclude animation. This currently ends instantly.
+ return new LaunchAnimator.State(
+ 0, height, 0, width, mWindowCornerRadius, mWindowCornerRadius);
+ }
+ };
+
+ private IRemoteAnimationRunner mOccludeAnimationRunner =
+ new ActivityLaunchRemoteAnimationRunner(mOccludeAnimationController);
+ private IRemoteAnimationRunner mUnoccludeAnimationRunner =
+ new ActivityLaunchRemoteAnimationRunner(mUnoccludeAnimationController);
+
private DeviceConfigProxy mDeviceConfig;
private DozeParameters mDozeParameters;
@@ -824,6 +936,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
private boolean mWallpaperSupportsAmbientMode;
private ScreenOnCoordinator mScreenOnCoordinator;
+ private Lazy<ActivityLaunchAnimator> mActivityLaunchAnimator;
+
/**
* Injected constructor. See {@link KeyguardModule}.
*/
@@ -850,7 +964,8 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
ScreenOnCoordinator screenOnCoordinator,
InteractionJankMonitor interactionJankMonitor,
DreamOverlayStateController dreamOverlayStateController,
- Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy) {
+ Lazy<NotificationShadeWindowController> notificationShadeWindowControllerLazy,
+ Lazy<ActivityLaunchAnimator> activityLaunchAnimator) {
super(context);
mFalsingCollector = falsingCollector;
mLockPatternUtils = lockPatternUtils;
@@ -890,6 +1005,12 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
mScreenOffAnimationController = screenOffAnimationController;
mInteractionJankMonitor = interactionJankMonitor;
mDreamOverlayStateController = dreamOverlayStateController;
+
+ mActivityLaunchAnimator = activityLaunchAnimator;
+
+ mPowerButtonY = context.getResources().getDimensionPixelSize(
+ R.dimen.physical_power_button_center_screen_location_y);
+ mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
}
public void userActivity() {
@@ -1440,6 +1561,14 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
Trace.endSection();
}
+ public IRemoteAnimationRunner getOccludeAnimationRunner() {
+ return mOccludeAnimationRunner;
+ }
+
+ public IRemoteAnimationRunner getUnoccludeAnimationRunner() {
+ return mUnoccludeAnimationRunner;
+ }
+
public boolean isHiding() {
return mHiding;
}
@@ -2868,4 +2997,36 @@ public class KeyguardViewMediator extends CoreStartable implements Dumpable,
return mMessage;
}
}
+
+ /**
+ * Implementation of RemoteAnimationRunner that creates a new
+ * {@link ActivityLaunchAnimator.Runner} whenever onAnimationStart is called, delegating the
+ * remote animation methods to that runner.
+ */
+ private class ActivityLaunchRemoteAnimationRunner extends IRemoteAnimationRunner.Stub {
+
+ private final ActivityLaunchAnimator.Controller mActivityLaunchController;
+ @Nullable private ActivityLaunchAnimator.Runner mRunner;
+
+ ActivityLaunchRemoteAnimationRunner(ActivityLaunchAnimator.Controller controller) {
+ mActivityLaunchController = controller;
+ }
+
+ @Override
+ public void onAnimationCancelled() throws RemoteException {
+ if (mRunner != null) {
+ mRunner.onAnimationCancelled();
+ }
+ }
+
+ @Override
+ public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
+ RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback)
+ throws RemoteException {
+ mRunner = mActivityLaunchAnimator.get().createRunner(mActivityLaunchController);
+ mRunner.onAnimationStart(transit, apps, wallpapers, nonApps, finishedCallback);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
index b49b49cbbb6d..195ef1a84c43 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java
@@ -32,6 +32,7 @@ import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
import com.android.keyguard.mediator.ScreenOnCoordinator;
+import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.classifier.FalsingModule;
@@ -102,7 +103,8 @@ public class KeyguardModule {
ScreenOnCoordinator screenOnCoordinator,
InteractionJankMonitor interactionJankMonitor,
DreamOverlayStateController dreamOverlayStateController,
- Lazy<NotificationShadeWindowController> notificationShadeWindowController) {
+ Lazy<NotificationShadeWindowController> notificationShadeWindowController,
+ Lazy<ActivityLaunchAnimator> activityLaunchAnimator) {
return new KeyguardViewMediator(
context,
falsingCollector,
@@ -128,8 +130,8 @@ public class KeyguardModule {
screenOnCoordinator,
interactionJankMonitor,
dreamOverlayStateController,
- notificationShadeWindowController
- );
+ notificationShadeWindowController,
+ activityLaunchAnimator);
}
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
index 86845091d99c..663877ce1388 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dagger/MediaModule.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.view.WindowManager;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
import com.android.systemui.media.MediaHost;
@@ -35,6 +36,7 @@ import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.commandline.CommandRegistry;
import java.util.Optional;
+import java.util.concurrent.Executor;
import javax.inject.Named;
@@ -99,13 +101,13 @@ public interface MediaModule {
@SysUISingleton
static Optional<MediaTttChipControllerSender> providesMediaTttChipControllerSender(
MediaTttFlags mediaTttFlags,
+ CommandQueue commandQueue,
Context context,
- WindowManager windowManager,
- CommandQueue commandQueue) {
+ WindowManager windowManager) {
if (!mediaTttFlags.isMediaTttEnabled()) {
return Optional.empty();
}
- return Optional.of(new MediaTttChipControllerSender(context, windowManager, commandQueue));
+ return Optional.of(new MediaTttChipControllerSender(commandQueue, context, windowManager));
}
/** */
@@ -128,6 +130,7 @@ public interface MediaModule {
MediaTttFlags mediaTttFlags,
CommandRegistry commandRegistry,
Context context,
+ @Main Executor mainExecutor,
MediaTttChipControllerReceiver mediaTttChipControllerReceiver) {
if (!mediaTttFlags.isMediaTttEnabled()) {
return Optional.empty();
@@ -136,6 +139,7 @@ public interface MediaModule {
new MediaTttCommandLineHelper(
commandRegistry,
context,
+ mainExecutor,
mediaTttChipControllerReceiver));
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamComplication.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamComplication.java
index 2c35db337cda..7c0481049098 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamComplication.java
@@ -37,6 +37,11 @@ public class MediaDreamComplication implements Complication {
}
@Override
+ public int getRequiredTypeAvailability() {
+ return COMPLICATION_TYPE_CAST_INFO;
+ }
+
+ @Override
public ViewHolder createView(ComplicationViewModel model) {
return mComponentFactory.create().getViewHolder();
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
index bbcbfba5bbe7..1ea21ce7728b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
@@ -21,13 +21,15 @@ import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Icon
import android.media.MediaRoute2Info
+import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
-import com.android.systemui.media.taptotransfer.sender.MoveCloserToEndCast
-import com.android.systemui.media.taptotransfer.sender.MoveCloserToStartCast
+import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast
+import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast
import com.android.systemui.media.taptotransfer.sender.TransferFailed
import com.android.systemui.media.taptotransfer.sender.TransferToReceiverTriggered
import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceSucceeded
@@ -36,6 +38,7 @@ import com.android.systemui.media.taptotransfer.sender.TransferToReceiverSucceed
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
import java.io.PrintWriter
+import java.util.concurrent.Executor
import javax.inject.Inject
/**
@@ -46,13 +49,36 @@ import javax.inject.Inject
class MediaTttCommandLineHelper @Inject constructor(
commandRegistry: CommandRegistry,
private val context: Context,
+ @Main private val mainExecutor: Executor,
private val mediaTttChipControllerReceiver: MediaTttChipControllerReceiver,
) {
- private val appIconDrawable =
+ private val appIconDrawable =
Icon.createWithResource(context, R.drawable.ic_avatar_user).loadDrawable(context).also {
it.setTint(Color.YELLOW)
}
+ /**
+ * A map from a display state string typed in the command line to the display int it represents.
+ */
+ private val stateStringToStateInt: Map<String, Int> = mapOf(
+ AlmostCloseToStartCast::class.simpleName!!
+ to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+ AlmostCloseToEndCast::class.simpleName!!
+ to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ TransferToReceiverTriggered::class.simpleName!!
+ to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
+ TransferToThisDeviceTriggered::class.simpleName!!
+ to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
+ TransferToReceiverSucceeded::class.simpleName!!
+ to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
+ TransferToThisDeviceSucceeded::class.simpleName!!
+ to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
+ TransferFailed::class.simpleName!!
+ to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
+ FAR_FROM_RECEIVER_STATE
+ to StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER
+ )
+
init {
commandRegistry.registerCommand(SENDER_COMMAND) { SenderCommand() }
commandRegistry.registerCommand(
@@ -68,22 +94,59 @@ class MediaTttCommandLineHelper @Inject constructor(
.addFeature("feature")
.build()
+ @StatusBarManager.MediaTransferSenderState
+ val displayState = stateStringToStateInt[args[1]]
+ if (displayState == null) {
+ pw.println("Invalid command name")
+ return
+ }
+
val statusBarManager = context.getSystemService(Context.STATUS_BAR_SERVICE)
as StatusBarManager
statusBarManager.updateMediaTapToTransferSenderDisplay(
- StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+ displayState,
routeInfo,
- /* undoExecutor= */ null,
- /* undoCallback= */ null
+ getUndoExecutor(displayState),
+ getUndoCallback(displayState)
)
- // TODO(b/216318437): Migrate the rest of the callbacks to StatusBarManager.
+ }
+
+ private fun getUndoExecutor(
+ @StatusBarManager.MediaTransferSenderState displayState: Int
+ ): Executor? {
+ return if (isSucceededState(displayState)) {
+ mainExecutor
+ } else {
+ null
+ }
+ }
+
+ private fun getUndoCallback(
+ @StatusBarManager.MediaTransferSenderState displayState: Int
+ ): Runnable? {
+ return if (isSucceededState(displayState)) {
+ Runnable { Log.i(CLI_TAG, "Undo triggered for $displayState") }
+ } else {
+ null
+ }
+ }
+
+ private fun isSucceededState(
+ @StatusBarManager.MediaTransferSenderState displayState: Int
+ ): Boolean {
+ return displayState ==
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED ||
+ displayState ==
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED
}
override fun help(pw: PrintWriter) {
- pw.println("Usage: adb shell cmd statusbar $SENDER_COMMAND <deviceName> <chipStatus>")
+ pw.println("Usage: adb shell cmd statusbar $SENDER_COMMAND <deviceName> <chipState>")
}
}
+ // TODO(b/216318437): Migrate the receiver callbacks to StatusBarManager.
+
/** A command to DISPLAY the media ttt chip on the RECEIVER device. */
inner class AddChipCommandReceiver : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
@@ -110,29 +173,15 @@ class MediaTttCommandLineHelper @Inject constructor(
@VisibleForTesting
const val SENDER_COMMAND = "media-ttt-chip-sender"
@VisibleForTesting
-const val REMOVE_CHIP_COMMAND_SENDER_TAG = "media-ttt-chip-remove-sender"
-@VisibleForTesting
const val ADD_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-add-receiver"
@VisibleForTesting
const val REMOVE_CHIP_COMMAND_RECEIVER_TAG = "media-ttt-chip-remove-receiver"
@VisibleForTesting
-val MOVE_CLOSER_TO_START_CAST_COMMAND_NAME = MoveCloserToStartCast::class.simpleName!!
-@VisibleForTesting
-val MOVE_CLOSER_TO_END_CAST_COMMAND_NAME = MoveCloserToEndCast::class.simpleName!!
-@VisibleForTesting
-val TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME = TransferToReceiverTriggered::class.simpleName!!
-@VisibleForTesting
-val TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME =
- TransferToThisDeviceTriggered::class.simpleName!!
-@VisibleForTesting
-val TRANSFER_TO_RECEIVER_SUCCEEDED_COMMAND_NAME = TransferToReceiverSucceeded::class.simpleName!!
-@VisibleForTesting
-val TRANSFER_TO_THIS_DEVICE_SUCCEEDED_COMMAND_NAME =
- TransferToThisDeviceSucceeded::class.simpleName!!
-@VisibleForTesting
-val TRANSFER_FAILED_COMMAND_NAME = TransferFailed::class.simpleName!!
-@VisibleForTesting
-val NO_LONGER_CLOSE_TO_RECEIVER_COMMAND_NAME = "NoLongerCloseToReceiver"
+val FAR_FROM_RECEIVER_STATE = "FarFromReceiver"
private const val APP_ICON_CONTENT_DESCRIPTION = "Fake media app icon"
-private const val TAG = "MediaTapToTransferCli"
+private const val CLI_TAG = "MediaTransferCli"
+
+private val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
+ .addFeature("feature")
+ .build() \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
index 118a04ccdcd0..05baf7806bda 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -59,7 +59,7 @@ sealed class ChipStateSender(
*
* @property otherDeviceName the name of the other device involved in the transfer.
*/
-class MoveCloserToStartCast(
+class AlmostCloseToStartCast(
appIconDrawable: Drawable,
appIconContentDescription: String,
private val otherDeviceName: String,
@@ -76,7 +76,7 @@ class MoveCloserToStartCast(
*
* @property otherDeviceName the name of the other device involved in the transfer.
*/
-class MoveCloserToEndCast(
+class AlmostCloseToEndCast(
appIconDrawable: Drawable,
appIconContentDescription: String,
private val otherDeviceName: String,
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index c510e358e4a5..d1790d2fd5e1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -21,6 +21,7 @@ import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Icon
import android.media.MediaRoute2Info
+import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
@@ -38,9 +39,9 @@ import javax.inject.Inject
*/
@SysUISingleton
class MediaTttChipControllerSender @Inject constructor(
+ commandQueue: CommandQueue,
context: Context,
windowManager: WindowManager,
- private val commandQueue: CommandQueue
) : MediaTttChipControllerCommon<ChipStateSender>(
context, windowManager, R.layout.media_ttt_chip
) {
@@ -50,25 +51,80 @@ class MediaTttChipControllerSender @Inject constructor(
it.setTint(Color.YELLOW)
}
- private val commandQueueCallback = object : CommandQueue.Callbacks {
+ private val commandQueueCallbacks = object : CommandQueue.Callbacks {
override fun updateMediaTapToTransferSenderDisplay(
@StatusBarManager.MediaTransferSenderState displayState: Int,
routeInfo: MediaRoute2Info,
undoCallback: IUndoMediaTransferCallback?
) {
- // TODO(b/216318437): Trigger displayChip with the right state based on displayState.
- displayChip(
- MoveCloserToStartCast(
- // TODO(b/217418566): This app icon content description is incorrect --
- // routeInfo.name is the name of the device, not the name of the app.
- fakeAppIconDrawable, routeInfo.name.toString(), routeInfo.name.toString()
- )
+ this@MediaTttChipControllerSender.updateMediaTapToTransferSenderDisplay(
+ displayState, routeInfo, undoCallback
)
}
}
init {
- commandQueue.addCallback(commandQueueCallback)
+ commandQueue.addCallback(commandQueueCallbacks)
+ }
+
+ private fun updateMediaTapToTransferSenderDisplay(
+ @StatusBarManager.MediaTransferSenderState displayState: Int,
+ routeInfo: MediaRoute2Info,
+ undoCallback: IUndoMediaTransferCallback?
+ ) {
+ // TODO(b/217418566): This app icon content description is incorrect --
+ // routeInfo.name is the name of the device, not the name of the app.
+ val appIconContentDescription = routeInfo.name.toString()
+ val otherDeviceName = routeInfo.name.toString()
+ val chipState = when(displayState) {
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST ->
+ AlmostCloseToStartCast(
+ fakeAppIconDrawable, appIconContentDescription, otherDeviceName
+ )
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST ->
+ AlmostCloseToEndCast(
+ fakeAppIconDrawable, appIconContentDescription, otherDeviceName
+ )
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED ->
+ TransferToReceiverTriggered(
+ fakeAppIconDrawable, appIconContentDescription, otherDeviceName
+ )
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED ->
+ TransferToThisDeviceTriggered(
+ fakeAppIconDrawable, appIconContentDescription
+ )
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED ->
+ TransferToReceiverSucceeded(
+ fakeAppIconDrawable,
+ appIconContentDescription,
+ otherDeviceName,
+ undoCallback
+ )
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED ->
+ TransferToThisDeviceSucceeded(
+ fakeAppIconDrawable,
+ appIconContentDescription,
+ otherDeviceName,
+ undoCallback
+ )
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED ->
+ TransferFailed(
+ fakeAppIconDrawable, appIconContentDescription
+ )
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER -> {
+ removeChip()
+ null
+ }
+ else -> {
+ Log.e(SENDER_TAG, "Unhandled MediaTransferSenderState $displayState")
+ null
+ }
+ }
+
+ chipState?.let {
+ displayChip(it)
+ }
}
/** Displays the chip view for the given state. */
@@ -97,3 +153,5 @@ class MediaTttChipControllerSender @Inject constructor(
if (showFailure) { View.VISIBLE } else { View.GONE }
}
}
+
+const val SENDER_TAG = "MediaTapToTransferSender"
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
new file mode 100644
index 000000000000..eb3415639db6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -0,0 +1,430 @@
+/*
+ * 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 com.android.systemui.qs
+
+import android.app.IActivityManager
+import android.app.IForegroundServiceObserver
+import android.content.Context
+import android.content.pm.PackageManager
+import android.graphics.drawable.Drawable
+import android.os.IBinder
+import android.os.PowerExemptionManager
+import android.os.RemoteException
+import android.provider.DeviceConfig.NAMESPACE_SYSTEMUI
+import android.text.format.DateUtils
+import android.util.ArrayMap
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.GuardedBy
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.LinearLayoutManager
+import androidx.recyclerview.widget.RecyclerView
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED
+import com.android.systemui.R
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.DeviceConfigProxy
+import com.android.systemui.util.time.SystemClock
+import java.util.Objects
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import kotlin.math.max
+
+class FgsManagerController @Inject constructor(
+ private val context: Context,
+ @Main private val mainExecutor: Executor,
+ @Background private val backgroundExecutor: Executor,
+ private val systemClock: SystemClock,
+ private val activityManager: IActivityManager,
+ private val packageManager: PackageManager,
+ private val deviceConfigProxy: DeviceConfigProxy,
+ private val dialogLaunchAnimator: DialogLaunchAnimator
+) : IForegroundServiceObserver.Stub() {
+
+ companion object {
+ private val LOG_TAG = FgsManagerController::class.java.simpleName
+ }
+
+ private var isAvailable = false
+
+ private val lock = Any()
+
+ @GuardedBy("lock")
+ var initialized = false
+
+ @GuardedBy("lock")
+ private val runningServiceTokens = mutableMapOf<UserPackage, StartTimeAndTokens>()
+
+ @GuardedBy("lock")
+ private var dialog: SystemUIDialog? = null
+
+ @GuardedBy("lock")
+ private val appListAdapter: AppListAdapter = AppListAdapter()
+
+ @GuardedBy("lock")
+ private var runningApps: ArrayMap<UserPackage, RunningApp> = ArrayMap()
+
+ interface OnNumberOfPackagesChangedListener {
+ fun onNumberOfPackagesChanged(numPackages: Int)
+ }
+
+ interface OnDialogDismissedListener {
+ fun onDialogDismissed()
+ }
+
+ fun init() {
+ synchronized(lock) {
+ if (initialized) {
+ return
+ }
+ try {
+ activityManager.registerForegroundServiceObserver(this)
+ } catch (e: RemoteException) {
+ e.rethrowFromSystemServer()
+ }
+
+ deviceConfigProxy.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI,
+ backgroundExecutor) {
+ isAvailable = it.getBoolean(TASK_MANAGER_ENABLED, isAvailable)
+ }
+
+ isAvailable = deviceConfigProxy
+ .getBoolean(NAMESPACE_SYSTEMUI, TASK_MANAGER_ENABLED, false)
+
+ initialized = true
+ }
+ }
+
+ override fun onForegroundStateChanged(
+ token: IBinder,
+ packageName: String,
+ userId: Int,
+ isForeground: Boolean
+ ) {
+ synchronized(lock) {
+ val numPackagesBefore = getNumRunningPackagesLocked()
+ val userPackageKey = UserPackage(userId, packageName)
+ if (isForeground) {
+ runningServiceTokens.getOrPut(userPackageKey, { StartTimeAndTokens(systemClock) })
+ .addToken(token)
+ } else {
+ if (runningServiceTokens[userPackageKey]?.also {
+ it.removeToken(token) }?.isEmpty() == true) {
+ runningServiceTokens.remove(userPackageKey)
+ }
+ }
+
+ val numPackagesAfter = getNumRunningPackagesLocked()
+
+ if (numPackagesAfter != numPackagesBefore) {
+ onNumberOfPackagesChangedListeners.forEach {
+ backgroundExecutor.execute { it.onNumberOfPackagesChanged(numPackagesAfter) }
+ }
+ }
+
+ updateAppItemsLocked()
+ }
+ }
+
+ @GuardedBy("lock")
+ val onNumberOfPackagesChangedListeners: MutableSet<OnNumberOfPackagesChangedListener> =
+ mutableSetOf()
+
+ @GuardedBy("lock")
+ val onDialogDismissedListeners: MutableSet<OnDialogDismissedListener> = mutableSetOf()
+
+ fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) {
+ synchronized(lock) {
+ onNumberOfPackagesChangedListeners.add(listener)
+ }
+ }
+
+ fun removeOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) {
+ synchronized(lock) {
+ onNumberOfPackagesChangedListeners.remove(listener)
+ }
+ }
+
+ fun addOnDialogDismissedListener(listener: OnDialogDismissedListener) {
+ synchronized(lock) {
+ onDialogDismissedListeners.add(listener)
+ }
+ }
+
+ fun removeOnDialogDismissedListener(listener: OnDialogDismissedListener) {
+ synchronized(lock) {
+ onDialogDismissedListeners.remove(listener)
+ }
+ }
+
+ fun isAvailable(): Boolean {
+ return isAvailable
+ }
+
+ fun getNumRunningPackages(): Int {
+ synchronized(lock) {
+ return getNumRunningPackagesLocked()
+ }
+ }
+
+ private fun getNumRunningPackagesLocked() =
+ runningServiceTokens.keys.count { it.uiControl != UIControl.HIDE_ENTRY }
+
+ fun shouldUpdateFooterVisibility() = dialog == null
+
+ fun showDialog(viewLaunchedFrom: View?) {
+ synchronized(lock) {
+ if (dialog == null) {
+
+ val dialog = SystemUIDialog(context)
+ dialog.setTitle(R.string.fgs_manager_dialog_title)
+
+ val dialogContext = dialog.context
+
+ val recyclerView = RecyclerView(dialogContext)
+ recyclerView.layoutManager = LinearLayoutManager(dialogContext)
+ recyclerView.adapter = appListAdapter
+
+ dialog.setView(recyclerView)
+
+ this.dialog = dialog
+
+ dialog.setOnDismissListener {
+ synchronized(lock) {
+ this.dialog = null
+ updateAppItemsLocked()
+ }
+ onDialogDismissedListeners.forEach {
+ mainExecutor.execute(it::onDialogDismissed)
+ }
+ }
+
+ mainExecutor.execute {
+ viewLaunchedFrom
+ ?.let { dialogLaunchAnimator.showFromView(dialog, it) } ?: dialog.show()
+ }
+
+ backgroundExecutor.execute {
+ synchronized(lock) {
+ updateAppItemsLocked()
+ }
+ }
+ }
+ }
+ }
+
+ @GuardedBy("lock")
+ private fun updateAppItemsLocked() {
+ if (dialog == null) {
+ runningApps.clear()
+ return
+ }
+
+ val addedPackages = runningServiceTokens.keys.filter {
+ it.uiControl != UIControl.HIDE_ENTRY && runningApps[it]?.stopped != true
+ }
+ val removedPackages = runningApps.keys.filter { !runningServiceTokens.containsKey(it) }
+
+ addedPackages.forEach {
+ val ai = packageManager.getApplicationInfoAsUser(it.packageName, 0, it.userId)
+ runningApps[it] = RunningApp(it.userId, it.packageName,
+ runningServiceTokens[it]!!.startTime, it.uiControl,
+ ai.loadLabel(packageManager), ai.loadIcon(packageManager))
+ }
+
+ removedPackages.forEach { pkg ->
+ val ra = runningApps[pkg]!!
+ val ra2 = ra.copy().also {
+ it.stopped = true
+ it.appLabel = ra.appLabel
+ it.icon = ra.icon
+ }
+ runningApps[pkg] = ra2
+ }
+
+ mainExecutor.execute {
+ appListAdapter
+ .setData(runningApps.values.toList().sortedByDescending { it.timeStarted })
+ }
+ }
+
+ private fun stopPackage(userId: Int, packageName: String) {
+ activityManager.stopAppForUser(packageName, userId)
+ }
+
+ private inner class AppListAdapter : RecyclerView.Adapter<AppItemViewHolder>() {
+ private val lock = Any()
+
+ @GuardedBy("lock")
+ private var data: List<RunningApp> = listOf()
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppItemViewHolder {
+ return AppItemViewHolder(LayoutInflater.from(parent.context)
+ .inflate(R.layout.fgs_manager_app_item, parent, false))
+ }
+
+ override fun onBindViewHolder(holder: AppItemViewHolder, position: Int) {
+ var runningApp: RunningApp
+ synchronized(lock) {
+ runningApp = data[position]
+ }
+ with(holder) {
+ iconView.setImageDrawable(runningApp.icon)
+ appLabelView.text = runningApp.appLabel
+ durationView.text = DateUtils.formatDuration(
+ max(systemClock.elapsedRealtime() - runningApp.timeStarted, 60000),
+ DateUtils.LENGTH_MEDIUM)
+ stopButton.setOnClickListener {
+ stopButton.setText(R.string.fgs_manager_app_item_stop_button_stopped_label)
+ stopPackage(runningApp.userId, runningApp.packageName)
+ }
+ if (runningApp.uiControl == UIControl.HIDE_BUTTON) {
+ stopButton.visibility = View.INVISIBLE
+ }
+ if (runningApp.stopped) {
+ stopButton.isEnabled = false
+ stopButton.setText(R.string.fgs_manager_app_item_stop_button_stopped_label)
+ durationView.visibility = View.GONE
+ } else {
+ stopButton.isEnabled = true
+ stopButton.setText(R.string.fgs_manager_app_item_stop_button_label)
+ durationView.visibility = View.VISIBLE
+ }
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return data.size
+ }
+
+ fun setData(newData: List<RunningApp>) {
+ var oldData = data
+ data = newData
+
+ DiffUtil.calculateDiff(object : DiffUtil.Callback() {
+ override fun getOldListSize(): Int {
+ return oldData.size
+ }
+
+ override fun getNewListSize(): Int {
+ return newData.size
+ }
+
+ override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int):
+ Boolean {
+ return oldData[oldItemPosition] == newData[newItemPosition]
+ }
+
+ override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int):
+ Boolean {
+ return oldData[oldItemPosition].stopped == newData[newItemPosition].stopped
+ }
+ }).dispatchUpdatesTo(this)
+ }
+ }
+
+ private inner class UserPackage(
+ val userId: Int,
+ val packageName: String
+ ) {
+ val uiControl: UIControl by lazy {
+ val uid = packageManager.getPackageUidAsUser(packageName, userId)
+
+ when (activityManager.getBackgroundRestrictionExemptionReason(uid)) {
+ PowerExemptionManager.REASON_SYSTEM_UID,
+ PowerExemptionManager.REASON_DEVICE_DEMO_MODE -> UIControl.HIDE_ENTRY
+
+ PowerExemptionManager.REASON_DEVICE_OWNER,
+ PowerExemptionManager.REASON_PROFILE_OWNER,
+ PowerExemptionManager.REASON_PROC_STATE_PERSISTENT,
+ PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI,
+ PowerExemptionManager.REASON_ROLE_DIALER,
+ PowerExemptionManager.REASON_SYSTEM_MODULE -> UIControl.HIDE_BUTTON
+ else -> UIControl.NORMAL
+ }
+ }
+
+ override fun equals(other: Any?): Boolean {
+ if (other !is UserPackage) {
+ return false
+ }
+ return other.packageName == packageName && other.userId == userId
+ }
+
+ override fun hashCode(): Int = Objects.hash(userId, packageName)
+ }
+
+ private data class StartTimeAndTokens(
+ val systemClock: SystemClock
+ ) {
+ val startTime = systemClock.elapsedRealtime()
+ val tokens = mutableSetOf<IBinder>()
+
+ fun addToken(token: IBinder) {
+ tokens.add(token)
+ }
+
+ fun removeToken(token: IBinder) {
+ tokens.remove(token)
+ }
+
+ fun isEmpty(): Boolean {
+ return tokens.isEmpty()
+ }
+ }
+
+ private class AppItemViewHolder(parent: View) : RecyclerView.ViewHolder(parent) {
+ val appLabelView: TextView = parent.requireViewById(R.id.fgs_manager_app_item_label)
+ val durationView: TextView = parent.requireViewById(R.id.fgs_manager_app_item_duration)
+ val iconView: ImageView = parent.requireViewById(R.id.fgs_manager_app_item_icon)
+ val stopButton: Button = parent.requireViewById(R.id.fgs_manager_app_item_stop_button)
+ }
+
+ private data class RunningApp(
+ val userId: Int,
+ val packageName: String,
+ val timeStarted: Long,
+ val uiControl: UIControl
+ ) {
+ constructor(
+ userId: Int,
+ packageName: String,
+ timeStarted: Long,
+ uiControl: UIControl,
+ appLabel: CharSequence,
+ icon: Drawable
+ ) : this(userId, packageName, timeStarted, uiControl) {
+ this.appLabel = appLabel
+ this.icon = icon
+ }
+
+ // variables to keep out of the generated equals()
+ var appLabel: CharSequence = ""
+ var icon: Drawable? = null
+ var stopped = false
+ }
+
+ private enum class UIControl {
+ NORMAL, HIDE_BUTTON, HIDE_ENTRY
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
index 082de1609423..55d4a53ced7b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java
@@ -16,13 +16,9 @@
package com.android.systemui.qs;
-import static android.provider.DeviceConfig.NAMESPACE_SYSTEMUI;
-
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED;
import static com.android.systemui.qs.dagger.QSFragmentModule.QS_FGS_MANAGER_FOOTER_VIEW;
import android.content.Context;
-import android.provider.DeviceConfig;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
@@ -30,8 +26,6 @@ import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.fgsmanager.FgsManagerDialogFactory;
-import com.android.systemui.statusbar.policy.RunningFgsController;
import java.util.concurrent.Executor;
@@ -41,24 +35,25 @@ import javax.inject.Named;
/**
* Footer entry point for the foreground service manager
*/
-public class QSFgsManagerFooter implements View.OnClickListener {
+public class QSFgsManagerFooter implements View.OnClickListener,
+ FgsManagerController.OnDialogDismissedListener,
+ FgsManagerController.OnNumberOfPackagesChangedListener {
private final View mRootView;
private final TextView mFooterText;
private final Context mContext;
private final Executor mMainExecutor;
private final Executor mExecutor;
- private final RunningFgsController mRunningFgsController;
- private final FgsManagerDialogFactory mFgsManagerDialogFactory;
+
+ private final FgsManagerController mFgsManagerController;
private boolean mIsInitialized = false;
- private boolean mIsAvailable = false;
+ private int mNumPackages;
@Inject
QSFgsManagerFooter(@Named(QS_FGS_MANAGER_FOOTER_VIEW) View rootView,
- @Main Executor mainExecutor, RunningFgsController runningFgsController,
- @Background Executor executor,
- FgsManagerDialogFactory fgsManagerDialogFactory) {
+ @Main Executor mainExecutor, @Background Executor executor,
+ FgsManagerController fgsManagerController) {
mRootView = rootView;
mFooterText = mRootView.findViewById(R.id.footer_text);
ImageView icon = mRootView.findViewById(R.id.primary_footer_icon);
@@ -66,8 +61,7 @@ public class QSFgsManagerFooter implements View.OnClickListener {
mContext = rootView.getContext();
mMainExecutor = mainExecutor;
mExecutor = executor;
- mRunningFgsController = runningFgsController;
- mFgsManagerDialogFactory = fgsManagerDialogFactory;
+ mFgsManagerController = fgsManagerController;
}
public void init() {
@@ -75,22 +69,28 @@ public class QSFgsManagerFooter implements View.OnClickListener {
return;
}
- mRootView.setOnClickListener(this);
-
- mRunningFgsController.addCallback(packages -> refreshState());
+ mFgsManagerController.init();
- DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_SYSTEMUI, mExecutor,
- (DeviceConfig.OnPropertiesChangedListener) properties -> {
- mIsAvailable = properties.getBoolean(TASK_MANAGER_ENABLED, mIsAvailable);
- });
- mIsAvailable = DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, TASK_MANAGER_ENABLED, false);
+ mRootView.setOnClickListener(this);
mIsInitialized = true;
}
+ public void setListening(boolean listening) {
+ if (listening) {
+ mFgsManagerController.addOnDialogDismissedListener(this);
+ mFgsManagerController.addOnNumberOfPackagesChangedListener(this);
+ mNumPackages = mFgsManagerController.getNumRunningPackages();
+ refreshState();
+ } else {
+ mFgsManagerController.removeOnDialogDismissedListener(this);
+ mFgsManagerController.removeOnNumberOfPackagesChangedListener(this);
+ }
+ }
+
@Override
public void onClick(View view) {
- mFgsManagerDialogFactory.create(mRootView);
+ mFgsManagerController.showDialog(mRootView);
}
public void refreshState() {
@@ -101,17 +101,25 @@ public class QSFgsManagerFooter implements View.OnClickListener {
return mRootView;
}
- private boolean isAvailable() {
- return mIsAvailable;
- }
-
public void handleRefreshState() {
- int numPackages = mRunningFgsController.getPackagesWithFgs().size();
mMainExecutor.execute(() -> {
mFooterText.setText(mContext.getResources().getQuantityString(
- R.plurals.fgs_manager_footer_label, numPackages, numPackages));
- mRootView.setVisibility(numPackages > 0 && isAvailable() ? View.VISIBLE : View.GONE);
+ R.plurals.fgs_manager_footer_label, mNumPackages, mNumPackages));
+ if (mFgsManagerController.shouldUpdateFooterVisibility()) {
+ mRootView.setVisibility(mNumPackages > 0
+ && mFgsManagerController.isAvailable() ? View.VISIBLE : View.GONE);
+ }
});
}
+ @Override
+ public void onDialogDismissed() {
+ refreshState();
+ }
+
+ @Override
+ public void onNumberOfPackagesChanged(int numPackages) {
+ mNumPackages = numPackages;
+ refreshState();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index cbfe944a2c23..8f268b5cffe4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -192,6 +192,7 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
refreshAllTiles();
}
+ mQSFgsManagerFooter.setListening(listening);
mQsSecurityFooter.setListening(listening);
// Set the listening as soon as the QS fragment starts listening regardless of the
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
index 48255b5360fc..6d1bbeed5372 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSModule.java
@@ -34,8 +34,6 @@ import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DeviceControlsController;
import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.RunningFgsController;
-import com.android.systemui.statusbar.policy.RunningFgsControllerImpl;
import com.android.systemui.statusbar.policy.WalletController;
import com.android.systemui.util.settings.SecureSettings;
@@ -91,9 +89,4 @@ public interface QSModule {
/** */
@Binds
QSHost provideQsHost(QSTileHost controllerImpl);
-
- /** */
- @Binds
- RunningFgsController provideRunningFgsController(
- RunningFgsControllerImpl runningFgsController);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 391525e11866..092e86daddb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -179,6 +179,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
if (!mNotifPipelineFlags.checkLegacyPipelineEnabled()) {
return;
}
+ Trace.beginSection("NotificationViewHierarchyManager.updateNotificationViews");
beginUpdate();
@@ -353,6 +354,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
mListContainer.onNotificationViewUpdateFinished();
endUpdate();
+ Trace.endSection();
}
/**
@@ -362,6 +364,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
* {@link com.android.systemui.statusbar.notification.collection.coordinator.StackCoordinator}
*/
private void updateNotifStats() {
+ Trace.beginSection("NotificationViewHierarchyManager.updateNotifStats");
boolean hasNonClearableAlertingNotifs = false;
boolean hasClearableAlertingNotifs = false;
boolean hasNonClearableSilentNotifs = false;
@@ -403,6 +406,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
hasNonClearableSilentNotifs /* hasNonClearableSilentNotifs */,
hasClearableSilentNotifs /* hasClearableSilentNotifs */
));
+ Trace.endSection();
}
/**
@@ -520,7 +524,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
}
private void updateRowStatesInternal() {
- Trace.beginSection("NotificationViewHierarchyManager#updateRowStates");
+ Trace.beginSection("NotificationViewHierarchyManager.updateRowStates");
final int N = mListContainer.getContainerChildCount();
int visibleNotifications = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 5302188ccb31..4a7606c316e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -22,6 +22,7 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.app.ActivityManager;
import android.app.Notification;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -33,7 +34,6 @@ import android.graphics.Color;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Parcelable;
@@ -57,6 +57,7 @@ import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.statusbar.notification.NotificationIconDozeHelper;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.util.drawable.DrawableSize;
import java.text.NumberFormat;
import java.util.Arrays;
@@ -84,16 +85,6 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
public static final int STATE_DOT = 1;
public static final int STATE_HIDDEN = 2;
- /**
- * Maximum allowed byte count for an icon bitmap
- * @see android.graphics.RecordingCanvas.MAX_BITMAP_SIZE
- */
- private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
- /**
- * Maximum allowed width or height for an icon drawable, if we can't get byte count
- */
- private static final int MAX_IMAGE_SIZE = 5000;
-
private static final String TAG = "StatusBarIconView";
private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
= new FloatProperty<StatusBarIconView>("iconAppearAmount") {
@@ -390,21 +381,6 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
return false;
}
- if (drawable instanceof BitmapDrawable && ((BitmapDrawable) drawable).getBitmap() != null) {
- // If it's a bitmap we can check the size directly
- int byteCount = ((BitmapDrawable) drawable).getBitmap().getByteCount();
- if (byteCount > MAX_BITMAP_SIZE) {
- Log.w(TAG, "Drawable is too large (" + byteCount + " bytes) " + mIcon);
- return false;
- }
- } else if (drawable.getIntrinsicWidth() > MAX_IMAGE_SIZE
- || drawable.getIntrinsicHeight() > MAX_IMAGE_SIZE) {
- // Otherwise, check dimensions
- Log.w(TAG, "Drawable is too large (" + drawable.getIntrinsicWidth() + "x"
- + drawable.getIntrinsicHeight() + ") " + mIcon);
- return false;
- }
-
if (withClear) {
setImageDrawable(null);
}
@@ -432,7 +408,7 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
* @return Drawable for this item, or null if the package or item could not
* be found
*/
- public static Drawable getIcon(Context sysuiContext,
+ private Drawable getIcon(Context sysuiContext,
Context context, StatusBarIcon statusBarIcon) {
int userId = statusBarIcon.user.getIdentifier();
if (userId == UserHandle.USER_ALL) {
@@ -446,6 +422,16 @@ public class StatusBarIconView extends AnimatedImageView implements StatusIconDi
typedValue, true);
float scaleFactor = typedValue.getFloat();
+ // We downscale the loaded drawable to reasonable size to protect against applications
+ // using too much memory. The size can be tweaked in config.xml. Drawables
+ // that are already sized properly won't be touched.
+ boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
+ Resources res = sysuiContext.getResources();
+ int maxIconSize = res.getDimensionPixelSize(isLowRamDevice
+ ? com.android.internal.R.dimen.notification_small_icon_size_low_ram
+ : com.android.internal.R.dimen.notification_small_icon_size);
+ icon = DrawableSize.downscaleToSize(res, icon, maxIconSize, maxIconSize);
+
// No need to scale the icon, so return it as is.
if (scaleFactor == 1.f) {
return icon;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index c33160858d0f..ad9f12ec3bc0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -24,6 +24,7 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking;
@@ -343,11 +344,14 @@ public class NotificationEntryManager implements
private final InflationCallback mInflationCallback = new InflationCallback() {
@Override
public void handleInflationException(NotificationEntry entry, Exception e) {
+ Trace.beginSection("NotificationEntryManager.handleInflationException");
NotificationEntryManager.this.handleInflationException(entry.getSbn(), e);
+ Trace.endSection();
}
@Override
public void onAsyncInflationFinished(NotificationEntry entry) {
+ Trace.beginSection("NotificationEntryManager.onAsyncInflationFinished");
mPendingNotifications.remove(entry.getKey());
// If there was an async task started after the removal, we don't want to add it back to
// the list, otherwise we might get leaks.
@@ -369,6 +373,7 @@ public class NotificationEntryManager implements
}
}
}
+ Trace.endSection();
}
};
@@ -463,6 +468,7 @@ public class NotificationEntryManager implements
boolean forceRemove,
DismissedByUserStats dismissedByUserStats,
int reason) {
+ Trace.beginSection("NotificationEntryManager.removeNotificationInternal");
final NotificationEntry entry = getActiveNotificationUnfiltered(key);
@@ -470,6 +476,7 @@ public class NotificationEntryManager implements
if (interceptor.onNotificationRemoveRequested(key, entry, reason)) {
// Remove intercepted; log and skip
mLogger.logRemovalIntercepted(key);
+ Trace.endSection();
return;
}
}
@@ -557,6 +564,7 @@ public class NotificationEntryManager implements
mLeakDetector.trackGarbage(entry);
}
}
+ Trace.endSection();
}
private void sendNotificationRemovalToServer(
@@ -620,6 +628,7 @@ public class NotificationEntryManager implements
private void addNotificationInternal(
StatusBarNotification notification,
RankingMap rankingMap) throws InflationException {
+ Trace.beginSection("NotificationEntryManager.addNotificationInternal");
String key = notification.getKey();
if (DEBUG) {
Log.d(TAG, "addNotification key=" + key);
@@ -667,6 +676,7 @@ public class NotificationEntryManager implements
for (NotifCollectionListener listener : mNotifCollectionListeners) {
listener.onRankingApplied();
}
+ Trace.endSection();
}
public void addNotification(StatusBarNotification notification, RankingMap ranking) {
@@ -679,12 +689,14 @@ public class NotificationEntryManager implements
private void updateNotificationInternal(StatusBarNotification notification,
RankingMap ranking) throws InflationException {
+ Trace.beginSection("NotificationEntryManager.updateNotificationInternal");
if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
final String key = notification.getKey();
abortExistingInflation(key, "updateNotification");
final NotificationEntry entry = getActiveNotificationUnfiltered(key);
if (entry == null) {
+ Trace.endSection();
return;
}
@@ -721,6 +733,7 @@ public class NotificationEntryManager implements
for (NotifCollectionListener listener : mNotifCollectionListeners) {
listener.onRankingApplied();
}
+ Trace.endSection();
}
public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
@@ -740,14 +753,17 @@ public class NotificationEntryManager implements
mLogger.logUseWhileNewPipelineActive("updateNotifications", reason);
return;
}
+ Trace.beginSection("NotificationEntryManager.updateNotifications");
reapplyFilterAndSort(reason);
if (mPresenter != null) {
mPresenter.updateNotificationViews(reason);
}
mNotifLiveDataStore.setActiveNotifList(getVisibleNotifications());
+ Trace.endSection();
}
public void updateNotificationRanking(RankingMap rankingMap) {
+ Trace.beginSection("NotificationEntryManager.updateNotificationRanking");
List<NotificationEntry> entries = new ArrayList<>();
entries.addAll(getVisibleNotifications());
entries.addAll(mPendingNotifications.values());
@@ -788,6 +804,7 @@ public class NotificationEntryManager implements
for (NotifCollectionListener listener : mNotifCollectionListeners) {
listener.onRankingApplied();
}
+ Trace.endSection();
}
void notifyChannelModified(
@@ -887,6 +904,7 @@ public class NotificationEntryManager implements
/** @return list of active notifications filtered for the current user */
public List<NotificationEntry> getActiveNotificationsForCurrentUser() {
+ Trace.beginSection("NotificationEntryManager.getActiveNotificationsForCurrentUser");
Assert.isMainThread();
ArrayList<NotificationEntry> filtered = new ArrayList<>();
@@ -898,7 +916,7 @@ public class NotificationEntryManager implements
}
filtered.add(entry);
}
-
+ Trace.endSection();
return filtered;
}
@@ -908,10 +926,12 @@ public class NotificationEntryManager implements
* @param reason the reason for calling this method, which will be logged
*/
public void updateRanking(RankingMap rankingMap, String reason) {
+ Trace.beginSection("NotificationEntryManager.updateRanking");
updateRankingAndSort(rankingMap, reason);
for (NotifCollectionListener listener : mNotifCollectionListeners) {
listener.onRankingApplied();
}
+ Trace.endSection();
}
/** Resorts / filters the current notification set with the current RankingMap */
@@ -920,7 +940,9 @@ public class NotificationEntryManager implements
mLogger.logUseWhileNewPipelineActive("reapplyFilterAndSort", reason);
return;
}
+ Trace.beginSection("NotificationEntryManager.reapplyFilterAndSort");
updateRankingAndSort(mRanker.getRankingMap(), reason);
+ Trace.endSection();
}
/** Calls to NotificationRankingManager and updates mSortedAndFiltered */
@@ -929,9 +951,11 @@ public class NotificationEntryManager implements
mLogger.logUseWhileNewPipelineActive("updateRankingAndSort", reason);
return;
}
+ Trace.beginSection("NotificationEntryManager.updateRankingAndSort");
mSortedAndFiltered.clear();
mSortedAndFiltered.addAll(mRanker.updateRanking(
rankingMap, mActiveNotifications.values(), reason));
+ Trace.endSection();
}
/** dump the current active notification list. Called from StatusBar */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index 74c97fdbddca..b328ae8cd0bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -226,8 +226,13 @@ public class ShadeListBuilder implements Dumpable {
mNotifSections.clear();
for (NotifSectioner sectioner : sectioners) {
- mNotifSections.add(new NotifSection(sectioner, mNotifSections.size()));
+ final NotifSection section = new NotifSection(sectioner, mNotifSections.size());
+ final NotifComparator sectionComparator = section.getComparator();
+ mNotifSections.add(section);
sectioner.setInvalidationListener(this::onNotifSectionInvalidated);
+ if (sectionComparator != null) {
+ sectionComparator.setInvalidationListener(this::onNotifComparatorInvalidated);
+ }
}
mNotifSections.add(new NotifSection(DEFAULT_SECTIONER, mNotifSections.size()));
@@ -426,14 +431,18 @@ public class ShadeListBuilder implements Dumpable {
}
Trace.endSection();
+ Trace.beginSection("ShadeListBuilder.logEndBuildList");
// Step 9: We're done!
mLogger.logEndBuildList(
mIterationCount,
mReadOnlyNotifList.size(),
countChildren(mReadOnlyNotifList));
if (mAlwaysLogList || mIterationCount % 10 == 0) {
+ Trace.beginSection("ShadeListBuilder.logFinalList");
mLogger.logFinalList(mNotifList);
+ Trace.endSection();
}
+ Trace.endSection();
mPipelineState.setState(STATE_IDLE);
mIterationCount++;
Trace.endSection();
@@ -996,16 +1005,20 @@ public class ShadeListBuilder implements Dumpable {
}
private void freeEmptyGroups() {
+ Trace.beginSection("ShadeListBuilder.freeEmptyGroups");
mGroups.values().removeIf(ge -> ge.getSummary() == null && ge.getChildren().isEmpty());
+ Trace.endSection();
}
private void logChanges() {
+ Trace.beginSection("ShadeListBuilder.logChanges");
for (NotificationEntry entry : mAllEntries) {
logAttachStateChanges(entry);
}
for (GroupEntry group : mGroups.values()) {
logAttachStateChanges(group);
}
+ Trace.endSection();
}
private void logAttachStateChanges(ListEntry entry) {
@@ -1083,16 +1096,23 @@ public class ShadeListBuilder implements Dumpable {
}
private void cleanupPluggables() {
+ Trace.beginSection("ShadeListBuilder.cleanupPluggables");
callOnCleanup(mNotifPreGroupFilters);
callOnCleanup(mNotifPromoters);
callOnCleanup(mNotifFinalizeFilters);
callOnCleanup(mNotifComparators);
for (int i = 0; i < mNotifSections.size(); i++) {
- mNotifSections.get(i).getSectioner().onCleanup();
+ final NotifSection notifSection = mNotifSections.get(i);
+ notifSection.getSectioner().onCleanup();
+ final NotifComparator comparator = notifSection.getComparator();
+ if (comparator != null) {
+ comparator.onCleanup();
+ }
}
callOnCleanup(List.of(getStabilityManager()));
+ Trace.endSection();
}
private void callOnCleanup(List<? extends Pluggable<?>> pluggables) {
@@ -1101,6 +1121,19 @@ public class ShadeListBuilder implements Dumpable {
}
}
+ @Nullable
+ private NotifComparator getSectionComparator(
+ @NonNull ListEntry o1, @NonNull ListEntry o2) {
+ final NotifSection section = o1.getSection();
+ if (section != o2.getSection()) {
+ throw new RuntimeException("Entry ordering should only be done within sections");
+ }
+ if (section != null) {
+ return section.getComparator();
+ }
+ return null;
+ }
+
private final Comparator<ListEntry> mTopLevelComparator = (o1, o2) -> {
int cmp = Integer.compare(
o1.getSectionIndex(),
@@ -1112,6 +1145,12 @@ public class ShadeListBuilder implements Dumpable {
cmp = Integer.compare(index1, index2);
if (cmp != 0) return cmp;
+ NotifComparator sectionComparator = getSectionComparator(o1, o2);
+ if (sectionComparator != null) {
+ cmp = sectionComparator.compare(o1, o2);
+ if (cmp != 0) return cmp;
+ }
+
for (int i = 0; i < mNotifComparators.size(); i++) {
cmp = mNotifComparators.get(i).compare(o1, o2);
if (cmp != 0) return cmp;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
index ba88ad7844f1..a390e9f9b09d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinator.kt
@@ -51,21 +51,18 @@ class ConversationCoordinator @Inject constructor(
val sectioner = object : NotifSectioner("People", BUCKET_PEOPLE) {
override fun isInSection(entry: ListEntry): Boolean =
isConversation(entry)
- override fun getHeaderNodeController() =
- // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and peopleHeaderController
- if (RankingCoordinator.SHOW_ALL_SECTIONS) peopleHeaderController else null
- }
- val comparator = object : NotifComparator("People") {
- override fun compare(entry1: ListEntry, entry2: ListEntry): Int {
- assert(entry1.section === entry2.section)
- if (entry1.section?.sectioner !== sectioner) {
- return 0
+ override fun getComparator() = object : NotifComparator("People") {
+ override fun compare(entry1: ListEntry, entry2: ListEntry): Int {
+ val type1 = getPeopleType(entry1)
+ val type2 = getPeopleType(entry2)
+ return type2.compareTo(type1)
}
- val type1 = getPeopleType(entry1)
- val type2 = getPeopleType(entry2)
- return type2.compareTo(type1)
}
+
+ override fun getHeaderNodeController() =
+ // TODO: remove SHOW_ALL_SECTIONS, this redundant method, and peopleHeaderController
+ if (RankingCoordinator.SHOW_ALL_SECTIONS) peopleHeaderController else null
}
override fun attach(pipeline: NotifPipeline) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index 031132424115..41b070635d4f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -26,6 +26,7 @@ import com.android.systemui.statusbar.notification.collection.ListEntry
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
@@ -456,6 +457,13 @@ class HeadsUpCoordinator @Inject constructor(
// TODO: This check won't notice if a child of the group is going to HUN...
isGoingToShowHunNoRetract(entry)
+ override fun getComparator(): NotifComparator {
+ return object : NotifComparator("HeadsUp") {
+ override fun compare(o1: ListEntry, o2: ListEntry): Int =
+ mHeadsUpManager.compare(o1.representativeEntry, o2.representativeEntry)
+ }
+ }
+
override fun getHeaderNodeController(): NodeController? =
// TODO: remove SHOW_ALL_SECTIONS, this redundant method, and mIncomingHeaderController
if (RankingCoordinator.SHOW_ALL_SECTIONS) mIncomingHeaderController else null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
index 850cb4b88154..757fb5a2fe9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt
@@ -20,7 +20,6 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.notification.NotifPipelineFlags
import com.android.systemui.statusbar.notification.collection.NotifPipeline
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
-import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import java.io.FileDescriptor
import java.io.PrintWriter
@@ -64,7 +63,6 @@ class NotifCoordinatorsImpl @Inject constructor(
private val mCoordinators: MutableList<Coordinator> = ArrayList()
private val mOrderedSections: MutableList<NotifSectioner> = ArrayList()
- private val mOrderedComparators: MutableList<NotifComparator> = ArrayList()
/**
* Creates all the coordinators.
@@ -119,9 +117,6 @@ class NotifCoordinatorsImpl @Inject constructor(
mOrderedSections.add(rankingCoordinator.alertingSectioner) // Alerting
mOrderedSections.add(rankingCoordinator.silentSectioner) // Silent
mOrderedSections.add(rankingCoordinator.minimizedSectioner) // Minimized
-
- // Manually add ordered comparators
- mOrderedComparators.add(conversationCoordinator.comparator)
}
/**
@@ -133,7 +128,6 @@ class NotifCoordinatorsImpl @Inject constructor(
c.attach(pipeline)
}
pipeline.setSections(mOrderedSections)
- pipeline.setComparators(mOrderedComparators)
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
index c6a8a69cfb0d..1c96e8ceb27f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StackCoordinator.kt
@@ -23,6 +23,7 @@ import com.android.systemui.statusbar.notification.collection.render.NotifStackC
import com.android.systemui.statusbar.notification.collection.render.NotifStats
import com.android.systemui.statusbar.notification.stack.BUCKET_SILENT
import com.android.systemui.statusbar.phone.NotificationIconAreaController
+import com.android.systemui.util.traceSection
import javax.inject.Inject
/**
@@ -38,10 +39,11 @@ class StackCoordinator @Inject internal constructor(
pipeline.addOnAfterRenderListListener(::onAfterRenderList)
}
- fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) {
- controller.setNotifStats(calculateNotifStats(entries))
- notificationIconAreaController.updateNotificationIcons(entries)
- }
+ fun onAfterRenderList(entries: List<ListEntry>, controller: NotifStackController) =
+ traceSection("StackCoordinator.onAfterRenderList") {
+ controller.setNotifStats(calculateNotifStats(entries))
+ notificationIconAreaController.updateNotificationIcons(entries)
+ }
private fun calculateNotifStats(entries: List<ListEntry>): NotifStats {
var hasNonClearableAlertingNotifs = false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
index 8444287cbf60..263737e20a13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifSection.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.listbuilder
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
import com.android.systemui.statusbar.notification.collection.render.NodeController
import com.android.systemui.statusbar.notification.stack.PriorityBucket
@@ -29,5 +30,7 @@ data class NotifSection(
val headerController: NodeController? = sectioner.headerNodeController
+ val comparator: NotifComparator? = sectioner.comparator
+
@PriorityBucket val bucket: Int = sectioner.bucket
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
index ef9ee11ef116..8c52c53ea6b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifSectioner.java
@@ -55,8 +55,22 @@ public abstract class NotifSectioner extends Pluggable<NotifSectioner> {
public abstract boolean isInSection(ListEntry entry);
/**
+ * Returns an optional {@link NotifComparator} to sort entries only in this section.
+ * {@link ListEntry} instances passed to this comparator are guaranteed to have this section,
+ * and this ordering will take precedence over any global comparators supplied to {@link
+ * com.android.systemui.statusbar.notification.collection.NotifPipeline#setComparators(List)}.
+ *
+ * NOTE: this method is only called once when the Sectioner is attached.
+ */
+ public @Nullable NotifComparator getComparator() {
+ return null;
+ }
+
+ /**
* Returns an optional {@link NodeSpec} for the section header. If {@code null}, no header will
* be used for the section.
+ *
+ * NOTE: this method is only called once when the Sectioner is attached.
*/
public @Nullable NodeController getHeaderNodeController() {
return null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
index 4de8e7a5641c..b76169f111db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/RootNodeController.kt
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification.collection.render
import android.view.View
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
@@ -41,6 +42,7 @@ class RootNodeController(
override fun addChildAt(child: NodeController, index: Int) {
listContainer.addContainerViewAt(child.view, index)
listContainer.onNotificationViewUpdateFinished()
+ (child.view as? ExpandableNotificationRow)?.isChangingPosition = false
}
override fun moveChildTo(child: NodeController, index: Int) {
@@ -50,6 +52,7 @@ class RootNodeController(
override fun removeChild(child: NodeController, isTransfer: Boolean) {
if (isTransfer) {
listContainer.setChildTransferInProgress(true)
+ (child.view as? ExpandableNotificationRow)?.isChangingPosition = true
}
listContainer.removeContainerView(child.view)
if (isTransfer) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 46efef66de43..2436ffdbeefa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -248,19 +248,25 @@ public class ExpandableNotificationRowController implements NotifViewController
mView.addChildNotification((ExpandableNotificationRow) child.getView(), index);
mListContainer.notifyGroupChildAdded(childView);
+ childView.setChangingPosition(false);
}
@Override
public void moveChildTo(NodeController child, int index) {
ExpandableNotificationRow childView = (ExpandableNotificationRow) child.getView();
+ childView.setChangingPosition(true);
mView.removeChildNotification(childView);
mView.addChildNotification(childView, index);
+ childView.setChangingPosition(false);
}
@Override
public void removeChild(NodeController child, boolean isTransfer) {
ExpandableNotificationRow childView = (ExpandableNotificationRow) child.getView();
+ if (isTransfer) {
+ childView.setChangingPosition(true);
+ }
mView.removeChildNotification(childView);
if (!isTransfer) {
mListContainer.notifyGroupChildRemoved(childView, mView);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index b02dc0cffdb9..54e26c34522d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -39,6 +39,7 @@ import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.children
import com.android.systemui.util.foldToSparseArray
import com.android.systemui.util.takeUntil
+import com.android.systemui.util.traceSection
import javax.inject.Inject
/**
@@ -157,7 +158,9 @@ class NotificationSectionsManager @Inject internal constructor(
}
}
}
- private fun logShadeContents() = parent.children.forEachIndexed(::logShadeChild)
+ private fun logShadeContents() = traceSection("NotifSectionsManager.logShadeContents") {
+ parent.children.forEachIndexed(::logShadeChild)
+ }
private val isUsingMultipleSections: Boolean
get() = sectionsFeatureManager.getNumberOfBuckets() > 1
@@ -221,10 +224,10 @@ class NotificationSectionsManager @Inject internal constructor(
* Should be called whenever notifs are added, removed, or updated. Updates section boundary
* bookkeeping and adds/moves/removes section headers if appropriate.
*/
- fun updateSectionBoundaries(reason: String) {
+ fun updateSectionBoundaries(reason: String) = traceSection("NotifSectionsManager.update") {
notifPipelineFlags.checkLegacyPipelineEnabled()
if (!isUsingMultipleSections) {
- return
+ return@traceSection
}
logger.logStartSectionUpdate(reason)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index dd72615768b0..25b8a6545638 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -43,7 +43,6 @@ import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Bundle;
-import android.os.UserHandle;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.IndentingPrintWriter;
@@ -696,8 +695,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
&& mQsExpansionFraction != 1
&& !mScreenOffAnimationController.shouldHideNotificationsFooter()
&& !mIsRemoteInputActive;
- boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
+ boolean showHistory = mController.isHistoryEnabled();
updateFooterView(showFooterView, showDismissView, showHistory);
}
@@ -5243,11 +5241,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
R.layout.status_bar_no_notifications, this, false);
view.setText(R.string.empty_shade_text);
view.setOnClickListener(v -> {
- final boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
- Intent intent = showHistory ? new Intent(
- Settings.ACTION_NOTIFICATION_HISTORY) : new Intent(
- Settings.ACTION_NOTIFICATION_SETTINGS);
+ final boolean showHistory = mController.isHistoryEnabled();
+ Intent intent = showHistory
+ ? new Intent(Settings.ACTION_NOTIFICATION_HISTORY)
+ : new Intent(Settings.ACTION_NOTIFICATION_SETTINGS);
mStatusBar.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
});
setEmptyShadeView(view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 334128a2b4ca..a2929f01f715 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -35,6 +35,8 @@ import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
+import android.os.Trace;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
@@ -180,7 +182,6 @@ public class NotificationStackScrollLayoutController {
private final NotificationLockscreenUserManager mLockscreenUserManager;
// TODO: StatusBar should be encapsulated behind a Controller
private final StatusBar mStatusBar;
- private final NotificationGroupManagerLegacy mLegacyGroupManager;
private final SectionHeaderController mSilentHeaderController;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
private final InteractionJankMonitor mJankMonitor;
@@ -191,6 +192,7 @@ public class NotificationStackScrollLayoutController {
private boolean mFadeNotificationsOnDismiss;
private NotificationSwipeHelper mSwipeHelper;
private boolean mShowEmptyShadeView;
+ @Nullable private Boolean mHistoryEnabled;
private int mBarState;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
@@ -340,6 +342,8 @@ public class NotificationStackScrollLayoutController {
@Override
public void onUserChanged(int userId) {
mView.updateSensitiveness(false, mLockscreenUserManager.isAnyProfilePublicMode());
+ mHistoryEnabled = null;
+ updateFooter();
}
};
@@ -699,8 +703,6 @@ public class NotificationStackScrollLayoutController {
}
});
mNotifPipelineFlags = notifPipelineFlags;
- mLegacyGroupManager = mNotifPipelineFlags.isNewPipelineEnabled()
- ? null : legacyGroupManager;
mSilentHeaderController = silentHeaderController;
mNotifPipeline = notifPipeline;
mNotifCollection = notifCollection;
@@ -802,6 +804,7 @@ public class NotificationStackScrollLayoutController {
(key, newValue) -> {
switch (key) {
case Settings.Secure.NOTIFICATION_HISTORY_ENABLED:
+ mHistoryEnabled = null; // invalidate
updateFooter();
break;
case HIGH_PRIORITY:
@@ -1009,6 +1012,20 @@ public class NotificationStackScrollLayoutController {
return mNotifStats.getNumActiveNotifs();
}
+ public boolean isHistoryEnabled() {
+ Boolean historyEnabled = mHistoryEnabled;
+ if (historyEnabled == null) {
+ if (mView == null || mView.getContext() == null) {
+ Log.wtf(TAG, "isHistoryEnabled failed to initialize its value");
+ return false;
+ }
+ mHistoryEnabled = historyEnabled =
+ Settings.Secure.getIntForUser(mView.getContext().getContentResolver(),
+ Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
+ }
+ return historyEnabled;
+ }
+
public int getIntrinsicContentHeight() {
return mView.getIntrinsicContentHeight();
}
@@ -1199,6 +1216,7 @@ public class NotificationStackScrollLayoutController {
* are true.
*/
public void updateShowEmptyShadeView() {
+ Trace.beginSection("NSSLC.updateShowEmptyShadeView");
mShowEmptyShadeView = mBarState != KEYGUARD
&& (!mView.isQsExpanded() || mView.isUsingSplitNotificationShade())
&& getVisibleNotificationCount() == 0;
@@ -1206,6 +1224,7 @@ public class NotificationStackScrollLayoutController {
mView.updateEmptyShadeView(
mShowEmptyShadeView,
mZenModeController.areNotificationsHiddenInShade());
+ Trace.endSection();
}
public boolean areNotificationsHiddenInShade() {
@@ -1323,11 +1342,15 @@ public class NotificationStackScrollLayoutController {
if (mNotifPipelineFlags.isNewPipelineEnabled()) {
return;
}
+ Trace.beginSection("NSSLC.updateSectionBoundaries");
mView.updateSectionBoundaries(reason);
+ Trace.endSection();
}
public void updateFooter() {
+ Trace.beginSection("NSSLC.updateFooter");
mView.updateFooter();
+ Trace.endSection();
}
public void onUpdateRowStates() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 3084a957aeb5..784a54681484 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -350,11 +350,14 @@ public abstract class HeadsUpManager extends AlertingNotificationManager {
* @return -1 if the first argument should be ranked higher than the second, 1 if the second
* one should be ranked higher and 0 if they are equal.
*/
- public int compare(@NonNull NotificationEntry a, @NonNull NotificationEntry b) {
+ public int compare(@Nullable NotificationEntry a, @Nullable NotificationEntry b) {
+ if (a == null || b == null) {
+ return Boolean.compare(a == null, b == null);
+ }
AlertEntry aEntry = getHeadsUpEntry(a.getKey());
AlertEntry bEntry = getHeadsUpEntry(b.getKey());
if (aEntry == null || bEntry == null) {
- return aEntry == null ? 1 : -1;
+ return Boolean.compare(aEntry == null, bEntry == null);
}
return aEntry.compareTo(bEntry);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsController.kt
deleted file mode 100644
index c6dbdb1b09a5..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsController.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.statusbar.policy
-
-/**
- * Interface for tracking packages with running foreground services and demoting foreground status
- */
-interface RunningFgsController : CallbackController<RunningFgsController.Callback> {
-
- /**
- * @return A list of [UserPackageTime]s which have running foreground service(s)
- */
- fun getPackagesWithFgs(): List<UserPackageTime>
-
- /**
- * Stops all foreground services running as a package
- * @param userId the userId the package is running under
- * @param packageName the packageName
- */
- fun stopFgs(userId: Int, packageName: String)
-
- /**
- * Returns when the list of packages with foreground services changes
- */
- interface Callback {
- /**
- * The thing that
- * @param packages the list of packages
- */
- fun onFgsPackagesChanged(packages: List<UserPackageTime>)
- }
-
- /**
- * A triplet <user, packageName, timeMillis> where each element is a package running
- * under a user that has had at least one foreground service running since timeMillis.
- * Time should be derived from [SystemClock.elapsedRealtime].
- */
- data class UserPackageTime(val userId: Int, val packageName: String, val startTimeMillis: Long)
-} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt
deleted file mode 100644
index 6d3345df4f3e..000000000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RunningFgsControllerImpl.kt
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.statusbar.policy
-
-import android.app.IActivityManager
-import android.app.IForegroundServiceObserver
-import android.os.IBinder
-import android.os.RemoteException
-import android.util.Log
-import androidx.annotation.GuardedBy
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleOwner
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.statusbar.policy.RunningFgsController.Callback
-import com.android.systemui.statusbar.policy.RunningFgsController.UserPackageTime
-import com.android.systemui.util.time.SystemClock
-import java.util.concurrent.Executor
-import javax.inject.Inject
-
-/**
- * Implementation for [RunningFgsController]
- */
-@SysUISingleton
-class RunningFgsControllerImpl @Inject constructor(
- @Background private val executor: Executor,
- private val systemClock: SystemClock,
- private val activityManager: IActivityManager
-) : RunningFgsController, IForegroundServiceObserver.Stub() {
-
- companion object {
- private val LOG_TAG = RunningFgsControllerImpl::class.java.simpleName
- }
-
- private val lock = Any()
-
- @GuardedBy("lock")
- var initialized = false
-
- @GuardedBy("lock")
- private val runningServiceTokens = mutableMapOf<UserPackageKey, StartTimeAndTokensValue>()
-
- @GuardedBy("lock")
- private val callbacks = mutableSetOf<Callback>()
-
- fun init() {
- synchronized(lock) {
- if (initialized) {
- return
- }
- try {
- activityManager.registerForegroundServiceObserver(this)
- } catch (e: RemoteException) {
- e.rethrowFromSystemServer()
- }
-
- initialized = true
- }
- }
-
- override fun addCallback(listener: Callback) {
- init()
- synchronized(lock) { callbacks.add(listener) }
- }
-
- override fun removeCallback(listener: Callback) {
- init()
- synchronized(lock) {
- if (!callbacks.remove(listener)) {
- Log.e(LOG_TAG, "Callback was not registered.", RuntimeException())
- }
- }
- }
-
- override fun observe(lifecycle: Lifecycle?, listener: Callback?): Callback {
- init()
- return super.observe(lifecycle, listener)
- }
-
- override fun observe(owner: LifecycleOwner?, listener: Callback?): Callback {
- init()
- return super.observe(owner, listener)
- }
-
- override fun getPackagesWithFgs(): List<UserPackageTime> {
- init()
- return synchronized(lock) { getPackagesWithFgsLocked() }
- }
-
- private fun getPackagesWithFgsLocked(): List<UserPackageTime> =
- runningServiceTokens.map {
- UserPackageTime(it.key.userId, it.key.packageName, it.value.fgsStartTime)
- }
-
- override fun stopFgs(userId: Int, packageName: String) {
- init()
- try {
- activityManager.stopAppForUser(packageName, userId)
- } catch (e: RemoteException) {
- e.rethrowFromSystemServer()
- }
- }
-
- private data class UserPackageKey(
- val userId: Int,
- val packageName: String
- )
-
- private class StartTimeAndTokensValue(systemClock: SystemClock) {
- val fgsStartTime = systemClock.elapsedRealtime()
- var tokens = mutableSetOf<IBinder>()
- fun addToken(token: IBinder): Boolean {
- return tokens.add(token)
- }
-
- fun removeToken(token: IBinder): Boolean {
- return tokens.remove(token)
- }
-
- val isEmpty: Boolean
- get() = tokens.isEmpty()
- }
-
- override fun onForegroundStateChanged(
- token: IBinder,
- packageName: String,
- userId: Int,
- isForeground: Boolean
- ) {
- val result = synchronized(lock) {
- val userPackageKey = UserPackageKey(userId, packageName)
- if (isForeground) {
- var addedNew = false
- runningServiceTokens.getOrPut(userPackageKey) {
- addedNew = true
- StartTimeAndTokensValue(systemClock)
- }.addToken(token)
- if (!addedNew) {
- return
- }
- } else {
- val startTimeAndTokensValue = runningServiceTokens[userPackageKey]
- if (startTimeAndTokensValue?.removeToken(token) == false) {
- Log.e(LOG_TAG,
- "Stopped foreground service was not known to be running.")
- return
- }
- if (!startTimeAndTokensValue!!.isEmpty) {
- return
- }
- runningServiceTokens.remove(userPackageKey)
- }
- getPackagesWithFgsLocked().toList()
- }
-
- callbacks.forEach { executor.execute { it.onFgsPackagesChanged(result) } }
- }
-} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt b/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
new file mode 100644
index 000000000000..b5068087d905
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/drawable/DrawableSize.kt
@@ -0,0 +1,123 @@
+package com.android.systemui.util.drawable
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.drawable.Animatable
+import android.graphics.drawable.Animatable2
+import android.graphics.drawable.AnimatedImageDrawable
+import android.graphics.drawable.AnimatedRotateDrawable
+import android.graphics.drawable.AnimatedStateListDrawable
+import android.graphics.drawable.AnimatedVectorDrawable
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import android.util.Log
+import androidx.annotation.Px
+import com.android.systemui.util.traceSection
+
+class DrawableSize {
+
+ companion object {
+
+ const val TAG = "SysUiDrawableSize"
+
+ /**
+ * Downscales passed Drawable to set maximum width and height. This will only
+ * be done for Drawables that can be downscaled non-destructively - e.g. animated
+ * and stateful drawables will no be downscaled.
+ *
+ * Downscaling will keep the aspect ratio.
+ * This method will not touch drawables that already fit into size specification.
+ *
+ * @param resources Resources on which to base the density of resized drawable.
+ * @param drawable Drawable to downscale.
+ * @param maxWidth Maximum width of the downscaled drawable.
+ * @param maxHeight Maximum height of the downscaled drawable.
+ *
+ * @return returns downscaled drawable if it's possible to downscale it or original if it's
+ * not.
+ */
+ @JvmStatic
+ fun downscaleToSize(
+ res: Resources,
+ drawable: Drawable,
+ @Px maxWidth: Int,
+ @Px maxHeight: Int
+ ): Drawable {
+ traceSection("DrawableSize#downscaleToSize") {
+ // Bitmap drawables can contain big bitmaps as their content while sneaking it past
+ // us using density scaling. Inspect inside the Bitmap drawables for actual bitmap
+ // size for those.
+ val originalWidth = (drawable as? BitmapDrawable)?.bitmap?.width
+ ?: drawable.intrinsicWidth
+ val originalHeight = (drawable as? BitmapDrawable)?.bitmap?.height
+ ?: drawable.intrinsicHeight
+
+ // Don't touch drawable if we can't resolve sizes for whatever reason.
+ if (originalWidth <= 0 || originalHeight <= 0) {
+ return drawable
+ }
+
+ // Do not touch drawables that are already within bounds.
+ if (originalWidth < maxWidth && originalHeight < maxHeight) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Not resizing $originalWidth x $originalHeight" + " " +
+ "to $maxWidth x $maxHeight")
+ }
+
+ return drawable
+ }
+
+ if (!isSimpleBitmap(drawable)) {
+ return drawable
+ }
+
+ val scaleWidth = maxWidth.toFloat() / originalWidth.toFloat()
+ val scaleHeight = maxHeight.toFloat() / originalHeight.toFloat()
+ val scale = minOf(scaleHeight, scaleWidth)
+
+ val width = (originalWidth * scale).toInt()
+ val height = (originalHeight * scale).toInt()
+
+ if (width <= 0 || height <= 0) {
+ Log.w(TAG, "Attempted to resize ${drawable.javaClass.simpleName} " +
+ "from $originalWidth x $originalHeight to invalid $width x $height.")
+ return drawable
+ }
+
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Resizing large drawable (${drawable.javaClass.simpleName}) " +
+ "from $originalWidth x $originalHeight to $width x $height")
+ }
+
+ // We want to keep existing config if it's more efficient than 32-bit RGB.
+ val config = (drawable as? BitmapDrawable)?.bitmap?.config
+ ?: Bitmap.Config.ARGB_8888
+ val scaledDrawableBitmap = Bitmap.createBitmap(width, height, config)
+ val canvas = Canvas(scaledDrawableBitmap)
+
+ val originalBounds = drawable.bounds
+ drawable.setBounds(0, 0, width, height)
+ drawable.draw(canvas)
+ drawable.bounds = originalBounds
+
+ return BitmapDrawable(res, scaledDrawableBitmap)
+ }
+ }
+
+ private fun isSimpleBitmap(drawable: Drawable): Boolean {
+ return !(drawable.isStateful || isAnimated(drawable))
+ }
+
+ private fun isAnimated(drawable: Drawable): Boolean {
+ if (drawable is Animatable || drawable is Animatable2) {
+ return true
+ }
+
+ return drawable is AnimatedImageDrawable ||
+ drawable is AnimatedRotateDrawable ||
+ drawable is AnimatedStateListDrawable ||
+ drawable is AnimatedVectorDrawable
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
index b951345a145b..61e78f5cb2fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/DialogLaunchAnimatorTest.kt
@@ -43,7 +43,7 @@ class DialogLaunchAnimatorTest : SysuiTestCase() {
@Before
fun setUp() {
dialogLaunchAnimator = DialogLaunchAnimator(
- dreamManager, launchAnimator, isForTesting = true)
+ dreamManager, launchAnimator, forceDisableSynchronization = true)
}
@After
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
index d5bd67adcf09..8adb55b8d6e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -36,7 +36,9 @@ import androidx.lifecycle.LifecycleRegistry;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.settingslib.dream.DreamBackend;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dreams.complication.Complication;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.touch.DreamOverlayTouchMonitor;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -50,6 +52,10 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayServiceTest extends SysuiTestCase {
@@ -94,11 +100,13 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
@Mock
DreamOverlayStateController mStateController;
+ @Mock
+ DreamBackend mDreamBackend;
DreamOverlayService mService;
@Before
- public void setup() throws Exception {
+ public void setup() {
MockitoAnnotations.initMocks(this);
mContext.addMockSystemService(WindowManager.class, mWindowManager);
@@ -110,6 +118,8 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
.thenReturn(mLifecycleRegistry);
when(mDreamOverlayComponent.getDreamOverlayTouchMonitor())
.thenReturn(mDreamOverlayTouchMonitor);
+ when(mDreamOverlayComponent.getDreamBackend())
+ .thenReturn(mDreamBackend);
when(mDreamOverlayComponentFactory
.create(any(), any()))
.thenReturn(mDreamOverlayComponent);
@@ -120,28 +130,34 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
mDreamOverlayComponentFactory,
mStateController,
mKeyguardUpdateMonitor);
+ }
+
+ @Test
+ public void testOverlayContainerViewAddedToWindow() throws Exception {
final IBinder proxy = mService.onBind(new Intent());
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
// Inform the overlay service of dream starting.
overlay.startDream(mWindowParams, mDreamOverlayCallback);
mMainExecutor.runAllReady();
- }
- @Test
- public void testOverlayContainerViewAddedToWindow() {
verify(mWindowManager).addView(any(), any());
}
@Test
- public void testDreamOverlayContainerViewControllerInitialized() {
+ public void testDreamOverlayContainerViewControllerInitialized() throws Exception {
+ final IBinder proxy = mService.onBind(new Intent());
+ final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
+
+ // Inform the overlay service of dream starting.
+ overlay.startDream(mWindowParams, mDreamOverlayCallback);
+ mMainExecutor.runAllReady();
+
verify(mDreamOverlayContainerViewController).init();
}
@Test
public void testShouldShowComplicationsTrueByDefault() {
- assertThat(mService.shouldShowComplications()).isTrue();
-
mService.onBind(new Intent());
assertThat(mService.shouldShowComplications()).isTrue();
@@ -155,4 +171,24 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
assertThat(mService.shouldShowComplications()).isFalse();
}
+
+ @Test
+ public void testSetAvailableComplicationTypes() throws Exception {
+ final Set<Integer> enabledComplications = new HashSet<>(
+ Arrays.asList(DreamBackend.COMPLICATION_TYPE_TIME,
+ DreamBackend.COMPLICATION_TYPE_DATE,
+ DreamBackend.COMPLICATION_TYPE_WEATHER));
+ when(mDreamBackend.getEnabledComplications()).thenReturn(enabledComplications);
+
+ final IBinder proxy = mService.onBind(new Intent());
+ final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
+
+ overlay.startDream(mWindowParams, mDreamOverlayCallback);
+ mMainExecutor.runAllReady();
+
+ final int expectedTypes =
+ Complication.COMPLICATION_TYPE_TIME | Complication.COMPLICATION_TYPE_DATE
+ | Complication.COMPLICATION_TYPE_WEATHER;
+ verify(mStateController).setAvailableComplicationTypes(expectedTypes);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationUtilsTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationUtilsTest.java
index f1978b214594..365c5291b118 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationUtilsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationUtilsTest.java
@@ -22,6 +22,7 @@ import static com.android.systemui.dreams.complication.Complication.COMPLICATION
import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_TIME;
import static com.android.systemui.dreams.complication.Complication.COMPLICATION_TYPE_WEATHER;
import static com.android.systemui.dreams.complication.ComplicationUtils.convertComplicationType;
+import static com.android.systemui.dreams.complication.ComplicationUtils.convertComplicationTypes;
import static com.google.common.truth.Truth.assertThat;
@@ -36,6 +37,11 @@ import com.android.systemui.SysuiTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class ComplicationUtilsTest extends SysuiTestCase {
@@ -52,4 +58,37 @@ public class ComplicationUtilsTest extends SysuiTestCase {
assertThat(convertComplicationType(DreamBackend.COMPLICATION_TYPE_CAST_INFO))
.isEqualTo(COMPLICATION_TYPE_CAST_INFO);
}
+
+ @Test
+ public void testConvertComplicationTypesEmpty() {
+ final Set<Integer> input = new HashSet<>();
+ final int expected = Complication.COMPLICATION_TYPE_NONE;
+
+ assertThat(convertComplicationTypes(input)).isEqualTo(expected);
+ }
+
+ @Test
+ public void testConvertComplicationTypesSingleValue() {
+ final Set<Integer> input = new HashSet<>(
+ Collections.singleton(DreamBackend.COMPLICATION_TYPE_WEATHER));
+ final int expected = Complication.COMPLICATION_TYPE_WEATHER;
+
+ assertThat(convertComplicationTypes(input)).isEqualTo(expected);
+ }
+
+ @Test
+ public void testConvertComplicationTypesSingleValueMultipleValues() {
+ final Set<Integer> input = new HashSet<>(
+ Arrays.asList(DreamBackend.COMPLICATION_TYPE_TIME,
+ DreamBackend.COMPLICATION_TYPE_DATE,
+ DreamBackend.COMPLICATION_TYPE_WEATHER,
+ DreamBackend.COMPLICATION_TYPE_AIR_QUALITY,
+ DreamBackend.COMPLICATION_TYPE_CAST_INFO));
+ final int expected =
+ Complication.COMPLICATION_TYPE_TIME | Complication.COMPLICATION_TYPE_DATE
+ | Complication.COMPLICATION_TYPE_WEATHER | COMPLICATION_TYPE_AIR_QUALITY
+ | COMPLICATION_TYPE_CAST_INFO;
+
+ assertThat(convertComplicationTypes(input)).isEqualTo(expected);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index d94e2eee9ffa..210cb82e1606 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -46,6 +46,7 @@ import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.mediator.ScreenOnCoordinator;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.dreams.DreamOverlayStateController;
@@ -100,6 +101,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock ScreenOnCoordinator mScreenOnCoordinator;
private @Mock Lazy<NotificationShadeWindowController> mNotificationShadeWindowControllerLazy;
private @Mock DreamOverlayStateController mDreamOverlayStateController;
+ private @Mock ActivityLaunchAnimator mActivityLaunchAnimator;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -205,7 +207,8 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
mScreenOnCoordinator,
mInteractionJankMonitor,
mDreamOverlayStateController,
- mNotificationShadeWindowControllerLazy);
+ mNotificationShadeWindowControllerLazy,
+ () -> mActivityLaunchAnimator);
mViewMediator.start();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
index 5f800eb80ec2..c3d8d245baed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
@@ -16,24 +16,35 @@
package com.android.systemui.media.taptotransfer
-import android.content.ComponentName
+import android.app.StatusBarManager
+import android.content.Context
+import android.media.MediaRoute2Info
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.media.taptotransfer.receiver.ChipStateReceiver
import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
+import com.android.systemui.media.taptotransfer.sender.AlmostCloseToEndCast
+import com.android.systemui.media.taptotransfer.sender.AlmostCloseToStartCast
+import com.android.systemui.media.taptotransfer.sender.TransferFailed
+import com.android.systemui.media.taptotransfer.sender.TransferToReceiverTriggered
+import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceSucceeded
+import com.android.systemui.media.taptotransfer.sender.TransferToThisDeviceTriggered
+import com.android.systemui.media.taptotransfer.sender.TransferToReceiverSucceeded
import com.android.systemui.statusbar.commandline.Command
import com.android.systemui.statusbar.commandline.CommandRegistry
+import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.mockito.nullable
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.mockito.Mock
-import org.mockito.Mockito.anyString
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
import java.io.PrintWriter
import java.io.StringWriter
@@ -50,15 +61,19 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
private lateinit var mediaTttCommandLineHelper: MediaTttCommandLineHelper
@Mock
+ private lateinit var statusBarManager: StatusBarManager
+ @Mock
private lateinit var mediaTttChipControllerReceiver: MediaTttChipControllerReceiver
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
+ context.addMockSystemService(Context.STATUS_BAR_SERVICE, statusBarManager)
mediaTttCommandLineHelper =
MediaTttCommandLineHelper(
commandRegistry,
context,
+ FakeExecutor(FakeSystemClock()),
mediaTttChipControllerReceiver,
)
}
@@ -88,91 +103,116 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
) { EmptyCommand() }
}
- /* TODO(b/216318437): Revive these tests using the new SystemApis.
@Test
- fun sender_moveCloserToStartCast_serviceCallbackCalled() {
- commandRegistry.onShellCommand(pw, getMoveCloserToStartCastCommand())
-
- assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
+ fun sender_almostCloseToStartCast_serviceCallbackCalled() {
+ commandRegistry.onShellCommand(
+ pw, getSenderCommand(AlmostCloseToStartCast::class.simpleName!!)
+ )
- val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
- verify(mediaSenderService).closeToReceiverToStartCast(any(), capture(deviceInfoCaptor))
- assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+ val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
+ verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+ eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST),
+ capture(routeInfoCaptor),
+ nullable(),
+ nullable())
+ assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
}
@Test
- fun sender_moveCloserToEndCast_serviceCallbackCalled() {
- commandRegistry.onShellCommand(pw, getMoveCloserToEndCastCommand())
-
- assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
+ fun sender_almostCloseToEndCast_serviceCallbackCalled() {
+ commandRegistry.onShellCommand(
+ pw, getSenderCommand(AlmostCloseToEndCast::class.simpleName!!)
+ )
- val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
- verify(mediaSenderService).closeToReceiverToEndCast(any(), capture(deviceInfoCaptor))
- assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+ val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
+ verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+ eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST),
+ capture(routeInfoCaptor),
+ nullable(),
+ nullable())
+ assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
}
@Test
fun sender_transferToReceiverTriggered_chipDisplayWithCorrectState() {
- commandRegistry.onShellCommand(pw, getTransferToReceiverTriggeredCommand())
-
- assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
+ commandRegistry.onShellCommand(
+ pw, getSenderCommand(TransferToReceiverTriggered::class.simpleName!!)
+ )
- val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
- verify(mediaSenderService).transferToReceiverTriggered(any(), capture(deviceInfoCaptor))
- assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+ val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
+ verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+ eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED),
+ capture(routeInfoCaptor),
+ nullable(),
+ nullable())
+ assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
}
@Test
fun sender_transferToThisDeviceTriggered_chipDisplayWithCorrectState() {
- commandRegistry.onShellCommand(pw, getTransferToThisDeviceTriggeredCommand())
+ commandRegistry.onShellCommand(
+ pw, getSenderCommand(TransferToThisDeviceTriggered::class.simpleName!!)
+ )
- assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
- verify(mediaSenderService).transferToThisDeviceTriggered(any(), any())
+ verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+ eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED),
+ any(),
+ nullable(),
+ nullable())
}
@Test
fun sender_transferToReceiverSucceeded_chipDisplayWithCorrectState() {
- commandRegistry.onShellCommand(pw, getTransferToReceiverSucceededCommand())
-
- assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
+ commandRegistry.onShellCommand(
+ pw, getSenderCommand(TransferToReceiverSucceeded::class.simpleName!!)
+ )
- val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
- verify(mediaSenderService)
- .transferToReceiverSucceeded(any(), capture(deviceInfoCaptor), any())
- assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+ val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
+ verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+ eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED),
+ capture(routeInfoCaptor),
+ nullable(),
+ nullable())
+ assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
}
@Test
fun sender_transferToThisDeviceSucceeded_chipDisplayWithCorrectState() {
- commandRegistry.onShellCommand(pw, getTransferToThisDeviceSucceededCommand())
-
- assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
+ commandRegistry.onShellCommand(
+ pw, getSenderCommand(TransferToThisDeviceSucceeded::class.simpleName!!)
+ )
- val deviceInfoCaptor = argumentCaptor<DeviceInfo>()
- verify(mediaSenderService)
- .transferToThisDeviceSucceeded(any(), capture(deviceInfoCaptor), any())
- assertThat(deviceInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
+ val routeInfoCaptor = argumentCaptor<MediaRoute2Info>()
+ verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+ eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED),
+ capture(routeInfoCaptor),
+ nullable(),
+ nullable())
+ assertThat(routeInfoCaptor.value!!.name).isEqualTo(DEVICE_NAME)
}
@Test
fun sender_transferFailed_serviceCallbackCalled() {
- commandRegistry.onShellCommand(pw, getTransferFailedCommand())
+ commandRegistry.onShellCommand(pw, getSenderCommand(TransferFailed::class.simpleName!!))
- assertThat(context.isBound(mediaSenderServiceComponentName)).isTrue()
- verify(mediaSenderService).transferFailed(any(), any())
+ verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+ eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED),
+ any(),
+ nullable(),
+ nullable())
}
@Test
- fun sender_noLongerCloseToReceiver_serviceCallbackCalledAndServiceUnbound() {
- commandRegistry.onShellCommand(pw, getNoLongerCloseToReceiverCommand())
-
- // Once we're no longer close to the receiver, we should unbind the service.
- assertThat(context.isBound(mediaSenderServiceComponentName)).isFalse()
- verify(mediaSenderService).noLongerCloseToReceiver(any(), any())
+ fun sender_farFromReceiver_serviceCallbackCalled() {
+ commandRegistry.onShellCommand(pw, getSenderCommand(FAR_FROM_RECEIVER_STATE))
+
+ verify(statusBarManager).updateMediaTapToTransferSenderDisplay(
+ eq(StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER),
+ any(),
+ nullable(),
+ nullable())
}
- */
-
@Test
fun receiver_addCommand_chipAdded() {
commandRegistry.onShellCommand(pw, arrayOf(ADD_CHIP_COMMAND_RECEIVER_TAG))
@@ -187,61 +227,8 @@ class MediaTttCommandLineHelperTest : SysuiTestCase() {
verify(mediaTttChipControllerReceiver).removeChip()
}
- private fun getMoveCloserToStartCastCommand(): Array<String> =
- arrayOf(
- SENDER_COMMAND,
- DEVICE_NAME,
- MOVE_CLOSER_TO_START_CAST_COMMAND_NAME
- )
-
- private fun getMoveCloserToEndCastCommand(): Array<String> =
- arrayOf(
- SENDER_COMMAND,
- DEVICE_NAME,
- MOVE_CLOSER_TO_END_CAST_COMMAND_NAME
- )
-
- private fun getTransferToReceiverTriggeredCommand(): Array<String> =
- arrayOf(
- SENDER_COMMAND,
- DEVICE_NAME,
- TRANSFER_TO_RECEIVER_TRIGGERED_COMMAND_NAME
- )
-
- private fun getTransferToThisDeviceTriggeredCommand(): Array<String> =
- arrayOf(
- SENDER_COMMAND,
- DEVICE_NAME,
- TRANSFER_TO_THIS_DEVICE_TRIGGERED_COMMAND_NAME
- )
-
- private fun getTransferToReceiverSucceededCommand(): Array<String> =
- arrayOf(
- SENDER_COMMAND,
- DEVICE_NAME,
- TRANSFER_TO_RECEIVER_SUCCEEDED_COMMAND_NAME
- )
-
- private fun getTransferToThisDeviceSucceededCommand(): Array<String> =
- arrayOf(
- SENDER_COMMAND,
- DEVICE_NAME,
- TRANSFER_TO_THIS_DEVICE_SUCCEEDED_COMMAND_NAME
- )
-
- private fun getTransferFailedCommand(): Array<String> =
- arrayOf(
- SENDER_COMMAND,
- DEVICE_NAME,
- TRANSFER_FAILED_COMMAND_NAME
- )
-
- private fun getNoLongerCloseToReceiverCommand(): Array<String> =
- arrayOf(
- SENDER_COMMAND,
- DEVICE_NAME,
- NO_LONGER_CLOSE_TO_RECEIVER_COMMAND_NAME
- )
+ private fun getSenderCommand(displayState: String): Array<String> =
+ arrayOf(SENDER_COMMAND, DEVICE_NAME, displayState)
class EmptyCommand : Command {
override fun execute(pw: PrintWriter, args: List<String>) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index 58f4818b3de5..c74ac64656ad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -16,8 +16,10 @@
package com.android.systemui.media.taptotransfer.sender
+import android.app.StatusBarManager
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
+import android.media.MediaRoute2Info
import android.view.View
import android.view.WindowManager
import android.widget.ImageView
@@ -35,6 +37,7 @@ import org.junit.Ignore
import org.junit.Test
import org.mockito.ArgumentCaptor
import org.mockito.Mock
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -49,17 +52,148 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
private lateinit var windowManager: WindowManager
@Mock
private lateinit var commandQueue: CommandQueue
+ private lateinit var commandQueueCallback: CommandQueue.Callbacks
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
appIconDrawable = Icon.createWithResource(context, R.drawable.ic_cake).loadDrawable(context)
- controllerSender = MediaTttChipControllerSender(context, windowManager, commandQueue)
+ controllerSender = MediaTttChipControllerSender(commandQueue, context, windowManager)
+
+ val callbackCaptor = ArgumentCaptor.forClass(CommandQueue.Callbacks::class.java)
+ verify(commandQueue).addCallback(callbackCaptor.capture())
+ commandQueueCallback = callbackCaptor.value!!
+ }
+
+ @Test
+ fun commandQueueCallback_almostCloseToStartCast_triggersCorrectChip() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+ routeInfo,
+ null
+ )
+
+ assertThat(getChipView().getChipText())
+ .isEqualTo(almostCloseToStartCast().getChipTextString(context))
+ }
+
+ @Test
+ fun commandQueueCallback_almostCloseToEndCast_triggersCorrectChip() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_END_CAST,
+ routeInfo,
+ null
+ )
+
+ assertThat(getChipView().getChipText())
+ .isEqualTo(almostCloseToEndCast().getChipTextString(context))
+ }
+
+ @Test
+ fun commandQueueCallback_transferToReceiverTriggered_triggersCorrectChip() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_TRIGGERED,
+ routeInfo,
+ null
+ )
+
+ assertThat(getChipView().getChipText())
+ .isEqualTo(transferToReceiverTriggered().getChipTextString(context))
+ }
+
+ @Test
+ fun commandQueueCallback_transferToThisDeviceTriggered_triggersCorrectChip() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_TRIGGERED,
+ routeInfo,
+ null
+ )
+
+ assertThat(getChipView().getChipText())
+ .isEqualTo(transferToThisDeviceTriggered().getChipTextString(context))
+ }
+
+ @Test
+ fun commandQueueCallback_transferToReceiverSucceeded_triggersCorrectChip() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_SUCCEEDED,
+ routeInfo,
+ null
+ )
+
+ assertThat(getChipView().getChipText())
+ .isEqualTo(transferToReceiverSucceeded().getChipTextString(context))
}
@Test
- fun moveCloserToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
- val state = moveCloserToStartCast()
+ fun commandQueueCallback_transferToThisDeviceSucceeded_triggersCorrectChip() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_SUCCEEDED,
+ routeInfo,
+ null
+ )
+
+ assertThat(getChipView().getChipText())
+ .isEqualTo(transferToThisDeviceSucceeded().getChipTextString(context))
+ }
+
+ @Test
+ fun commandQueueCallback_transferToReceiverFailed_triggersCorrectChip() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_RECEIVER_FAILED,
+ routeInfo,
+ null
+ )
+
+ assertThat(getChipView().getChipText())
+ .isEqualTo(transferFailed().getChipTextString(context))
+ }
+
+ @Test
+ fun commandQueueCallback_transferToThisDeviceFailed_triggersCorrectChip() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_TRANSFER_TO_THIS_DEVICE_FAILED,
+ routeInfo,
+ null
+ )
+
+ assertThat(getChipView().getChipText())
+ .isEqualTo(transferFailed().getChipTextString(context))
+ }
+
+ @Test
+ fun commandQueueCallback_farFromReceiver_noChipShown() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+ routeInfo,
+ null
+ )
+
+ verify(windowManager, never()).addView(any(), any())
+ }
+
+ @Test
+ fun commandQueueCallback_almostCloseThenFarFromReceiver_chipShownThenHidden() {
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_ALMOST_CLOSE_TO_START_CAST,
+ routeInfo,
+ null
+ )
+
+ commandQueueCallback.updateMediaTapToTransferSenderDisplay(
+ StatusBarManager.MEDIA_TRANSFER_SENDER_STATE_FAR_FROM_RECEIVER,
+ routeInfo,
+ null
+ )
+
+ val viewCaptor = ArgumentCaptor.forClass(View::class.java)
+ verify(windowManager).addView(viewCaptor.capture(), any())
+ verify(windowManager).removeView(viewCaptor.value)
+ }
+
+ @Test
+ fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
+ val state = almostCloseToStartCast()
controllerSender.displayChip(state)
val chipView = getChipView()
@@ -72,8 +206,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
}
@Test
- fun moveCloserToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
- val state = moveCloserToEndCast()
+ fun almostCloseToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
+ val state = almostCloseToEndCast()
controllerSender.displayChip(state)
val chipView = getChipView()
@@ -250,8 +384,8 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
}
@Test
- fun changeFromCloserToStartToTransferTriggered_loadingIconAppears() {
- controllerSender.displayChip(moveCloserToStartCast())
+ fun changeFromAlmostCloseToStartToTransferTriggered_loadingIconAppears() {
+ controllerSender.displayChip(almostCloseToStartCast())
controllerSender.displayChip(transferToReceiverTriggered())
assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
@@ -280,9 +414,9 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
}
@Test
- fun changeFromTransferSucceededToMoveCloserToStart_undoButtonDisappears() {
+ fun changeFromTransferSucceededToAlmostCloseToStart_undoButtonDisappears() {
controllerSender.displayChip(transferToReceiverSucceeded())
- controllerSender.displayChip(moveCloserToStartCast())
+ controllerSender.displayChip(almostCloseToStartCast())
assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE)
}
@@ -314,12 +448,12 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
}
/** Helper method providing default parameters to not clutter up the tests. */
- private fun moveCloserToStartCast() =
- MoveCloserToStartCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
+ private fun almostCloseToStartCast() =
+ AlmostCloseToStartCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
/** Helper method providing default parameters to not clutter up the tests. */
- private fun moveCloserToEndCast() =
- MoveCloserToEndCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
+ private fun almostCloseToEndCast() =
+ AlmostCloseToEndCast(appIconDrawable, APP_ICON_CONTENT_DESC, DEVICE_NAME)
/** Helper method providing default parameters to not clutter up the tests. */
private fun transferToReceiverTriggered() =
@@ -347,3 +481,7 @@ class MediaTttChipControllerSenderTest : SysuiTestCase() {
private const val DEVICE_NAME = "My Tablet"
private const val APP_ICON_CONTENT_DESC = "Content description"
+
+private val routeInfo = MediaRoute2Info.Builder("id", "Test Name")
+ .addFeature("feature")
+ .build()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java
deleted file mode 100644
index 6059afe8a70b..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RunningFgsControllerTest.java
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.IActivityManager;
-import android.app.IForegroundServiceObserver;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.testing.AndroidTestingRunner;
-import android.util.Pair;
-
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.test.filters.MediumTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.policy.RunningFgsController;
-import com.android.systemui.statusbar.policy.RunningFgsController.UserPackageTime;
-import com.android.systemui.statusbar.policy.RunningFgsControllerImpl;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.Random;
-import java.util.function.Consumer;
-
-@MediumTest
-@RunWith(AndroidTestingRunner.class)
-public class RunningFgsControllerTest extends SysuiTestCase {
-
- private RunningFgsController mController;
-
- private FakeSystemClock mSystemClock = new FakeSystemClock();
- private FakeExecutor mExecutor = new FakeExecutor(mSystemClock);
- private TestCallback mCallback = new TestCallback();
-
- @Mock
- private IActivityManager mActivityManager;
- @Mock
- private Lifecycle mLifecycle;
- @Mock
- private LifecycleOwner mLifecycleOwner;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycle);
- mController = new RunningFgsControllerImpl(mExecutor, mSystemClock, mActivityManager);
- }
-
- @Test
- public void testInitRegistersListenerInImpl() throws RemoteException {
- ((RunningFgsControllerImpl) mController).init();
- verify(mActivityManager, times(1)).registerForegroundServiceObserver(any());
- }
-
- @Test
- public void testAddCallbackCallsInitInImpl() {
- verifyInitIsCalled(controller -> controller.addCallback(mCallback));
- }
-
- @Test
- public void testRemoveCallbackCallsInitInImpl() {
- verifyInitIsCalled(controller -> controller.removeCallback(mCallback));
- }
-
- @Test
- public void testObserve1CallsInitInImpl() {
- verifyInitIsCalled(controller -> controller.observe(mLifecycle, mCallback));
- }
-
- @Test
- public void testObserve2CallsInitInImpl() {
- verifyInitIsCalled(controller -> controller.observe(mLifecycleOwner, mCallback));
- }
-
- @Test
- public void testGetPackagesWithFgsCallsInitInImpl() {
- verifyInitIsCalled(controller -> controller.getPackagesWithFgs());
- }
-
- @Test
- public void testStopFgsCallsInitInImpl() {
- verifyInitIsCalled(controller -> controller.stopFgs(0, ""));
- }
-
- /**
- * Tests that callbacks can be added
- */
- @Test
- public void testAddCallback() throws RemoteException {
- String testPackageName = "testPackageName";
- int testUserId = 0;
-
- IForegroundServiceObserver observer = prepareObserver();
- mController.addCallback(mCallback);
-
- observer.onForegroundStateChanged(new Binder(), testPackageName, testUserId, true);
-
- mExecutor.advanceClockToLast();
- mExecutor.runAllReady();
-
- assertEquals("Callback should have been invoked exactly once.",
- 1, mCallback.mInvocations.size());
-
- List<UserPackageTime> userPackageTimes = mCallback.mInvocations.get(0);
- assertEquals("There should have only been one package in callback. packages="
- + userPackageTimes,
- 1, userPackageTimes.size());
-
- UserPackageTime upt = userPackageTimes.get(0);
- assertEquals(testPackageName, upt.getPackageName());
- assertEquals(testUserId, upt.getUserId());
- }
-
- /**
- * Tests that callbacks can be removed. This test is only meaningful if
- * {@link #testAddCallback()} can pass.
- */
- @Test
- public void testRemoveCallback() throws RemoteException {
- String testPackageName = "testPackageName";
- int testUserId = 0;
-
- IForegroundServiceObserver observer = prepareObserver();
- mController.addCallback(mCallback);
- mController.removeCallback(mCallback);
-
- observer.onForegroundStateChanged(new Binder(), testPackageName, testUserId, true);
-
- mExecutor.advanceClockToLast();
- mExecutor.runAllReady();
-
- assertEquals("Callback should not have been invoked.",
- 0, mCallback.mInvocations.size());
- }
-
- /**
- * Tests packages are added when the controller receives a callback from activity manager for
- * a foreground service start.
- */
- @Test
- public void testGetPackagesWithFgsAddingPackages() throws RemoteException {
- int numPackages = 20;
- int numUsers = 3;
-
- IForegroundServiceObserver observer = prepareObserver();
-
- assertEquals("List should be empty", 0, mController.getPackagesWithFgs().size());
-
- List<Pair<Integer, String>> addedPackages = new ArrayList<>();
- for (int pkgNumber = 0; pkgNumber < numPackages; pkgNumber++) {
- for (int userId = 0; userId < numUsers; userId++) {
- String packageName = "package.name." + pkgNumber;
- addedPackages.add(new Pair(userId, packageName));
-
- observer.onForegroundStateChanged(new Binder(), packageName, userId, true);
-
- containsAllAddedPackages(addedPackages, mController.getPackagesWithFgs());
- }
- }
- }
-
- /**
- * Tests packages are removed when the controller receives a callback from activity manager for
- * a foreground service ending.
- */
- @Test
- public void testGetPackagesWithFgsRemovingPackages() throws RemoteException {
- int numPackages = 20;
- int numUsers = 3;
- int arrayLength = numPackages * numUsers;
-
- String[] packages = new String[arrayLength];
- int[] users = new int[arrayLength];
- IBinder[] tokens = new IBinder[arrayLength];
- for (int pkgNumber = 0; pkgNumber < numPackages; pkgNumber++) {
- for (int userId = 0; userId < numUsers; userId++) {
- int i = pkgNumber * numUsers + userId;
- packages[i] = "package.name." + pkgNumber;
- users[i] = userId;
- tokens[i] = new Binder();
- }
- }
-
- IForegroundServiceObserver observer = prepareObserver();
-
- for (int i = 0; i < packages.length; i++) {
- observer.onForegroundStateChanged(tokens[i], packages[i], users[i], true);
- }
-
- assertEquals(packages.length, mController.getPackagesWithFgs().size());
-
- List<Integer> removeOrder = new ArrayList<>();
- for (int i = 0; i < packages.length; i++) {
- removeOrder.add(i);
- }
- Collections.shuffle(removeOrder, new Random(12345));
-
- for (int idx : removeOrder) {
- removePackageAndAssertRemovedFromList(observer, tokens[idx], packages[idx], users[idx]);
- }
-
- assertEquals(0, mController.getPackagesWithFgs().size());
- }
-
- /**
- * Tests a call on stopFgs forwards to activity manager.
- */
- @Test
- public void testStopFgs() throws RemoteException {
- String pkgName = "package.name";
- mController.stopFgs(0, pkgName);
- verify(mActivityManager).stopAppForUser(pkgName, 0);
- }
-
- /**
- * Tests a package which starts multiple services is only listed once and is only removed once
- * all services are stopped.
- */
- @Test
- public void testSinglePackageWithMultipleServices() throws RemoteException {
- String packageName = "package.name";
- int userId = 0;
- IBinder serviceToken1 = new Binder();
- IBinder serviceToken2 = new Binder();
-
- IForegroundServiceObserver observer = prepareObserver();
-
- assertEquals(0, mController.getPackagesWithFgs().size());
-
- observer.onForegroundStateChanged(serviceToken1, packageName, userId, true);
- assertSinglePackage(packageName, userId);
-
- observer.onForegroundStateChanged(serviceToken2, packageName, userId, true);
- assertSinglePackage(packageName, userId);
-
- observer.onForegroundStateChanged(serviceToken2, packageName, userId, false);
- assertSinglePackage(packageName, userId);
-
- observer.onForegroundStateChanged(serviceToken1, packageName, userId, false);
- assertEquals(0, mController.getPackagesWithFgs().size());
- }
-
- private IForegroundServiceObserver prepareObserver()
- throws RemoteException {
- mController.getPackagesWithFgs();
-
- ArgumentCaptor<IForegroundServiceObserver> argumentCaptor =
- ArgumentCaptor.forClass(IForegroundServiceObserver.class);
- verify(mActivityManager).registerForegroundServiceObserver(argumentCaptor.capture());
-
- return argumentCaptor.getValue();
- }
-
- private void verifyInitIsCalled(Consumer<RunningFgsControllerImpl> c) {
- RunningFgsControllerImpl spiedController = Mockito.spy(
- ((RunningFgsControllerImpl) mController));
- c.accept(spiedController);
- verify(spiedController, atLeastOnce()).init();
- }
-
- private void containsAllAddedPackages(List<Pair<Integer, String>> addedPackages,
- List<UserPackageTime> runningFgsPackages) {
- for (Pair<Integer, String> userPkg : addedPackages) {
- assertTrue(userPkg + " was not found in returned list",
- runningFgsPackages.stream().anyMatch(
- upt -> userPkg.first == upt.getUserId()
- && Objects.equals(upt.getPackageName(), userPkg.second)));
- }
- for (UserPackageTime upt : runningFgsPackages) {
- int userId = upt.getUserId();
- String packageName = upt.getPackageName();
- assertTrue("Unknown <user=" + userId + ", package=" + packageName + ">"
- + " in returned list",
- addedPackages.stream().anyMatch(userPkg -> userPkg.first == userId
- && Objects.equals(packageName, userPkg.second)));
- }
- }
-
- private void removePackageAndAssertRemovedFromList(IForegroundServiceObserver observer,
- IBinder token, String pkg, int userId) throws RemoteException {
- observer.onForegroundStateChanged(token, pkg, userId, false);
- List<UserPackageTime> packagesWithFgs = mController.getPackagesWithFgs();
- assertFalse("Package \"" + pkg + "\" was not removed",
- packagesWithFgs.stream().anyMatch(upt ->
- Objects.equals(upt.getPackageName(), pkg) && upt.getUserId() == userId));
- }
-
- private void assertSinglePackage(String packageName, int userId) {
- assertEquals(1, mController.getPackagesWithFgs().size());
- assertEquals(packageName, mController.getPackagesWithFgs().get(0).getPackageName());
- assertEquals(userId, mController.getPackagesWithFgs().get(0).getUserId());
- }
-
- private static class TestCallback implements RunningFgsController.Callback {
-
- private List<List<UserPackageTime>> mInvocations = new ArrayList<>();
-
- @Override
- public void onFgsPackagesChanged(List<UserPackageTime> packages) {
- mInvocations.add(packages);
- }
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
index 85ea52b6af6a..d13451dc4769 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar;
+import static com.google.common.truth.Truth.assertThat;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
@@ -37,6 +39,7 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Icon;
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
@@ -130,7 +133,12 @@ public class StatusBarIconViewTest extends SysuiTestCase {
Icon icon = Icon.createWithBitmap(largeBitmap);
StatusBarIcon largeIcon = new StatusBarIcon(UserHandle.ALL, "mockPackage",
icon, 0, 0, "");
- assertFalse(mIconView.set(largeIcon));
+ assertTrue(mIconView.set(largeIcon));
+
+ // The view should downscale the bitmap.
+ BitmapDrawable drawable = (BitmapDrawable) mIconView.getDrawable();
+ assertThat(drawable.getBitmap().getWidth()).isLessThan(1000);
+ assertThat(drawable.getBitmap().getHeight()).isLessThan(1000);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 8fb066bb4a39..cb248b05e4bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -29,6 +29,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.inOrder;
@@ -46,6 +47,7 @@ import android.testing.TestableLooper;
import android.util.ArrayMap;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
@@ -872,6 +874,73 @@ public class ShadeListBuilderTest extends SysuiTestCase {
}
@Test
+ public void testThatSectionComparatorsAreCalled() {
+ // GIVEN a section with a comparator that elevates some packages over others
+ NotifComparator comparator = spy(new HypeComparator(PACKAGE_2, PACKAGE_4));
+ NotifSectioner sectioner = new PackageSectioner(
+ List.of(PACKAGE_1, PACKAGE_2, PACKAGE_4, PACKAGE_5), comparator);
+ mListBuilder.setSectioners(List.of(sectioner));
+
+ // WHEN the pipeline is kicked off on a bunch of notifications
+ addNotif(0, PACKAGE_0);
+ addNotif(1, PACKAGE_1);
+ addNotif(2, PACKAGE_2);
+ addNotif(3, PACKAGE_3);
+ addNotif(4, PACKAGE_4);
+ addNotif(5, PACKAGE_5);
+ dispatchBuild();
+
+ // THEN the notifs are sorted according to both sectioning and the section's comparator
+ verifyBuiltList(
+ notif(2),
+ notif(4),
+ notif(1),
+ notif(5),
+ notif(0),
+ notif(3)
+ );
+
+ // VERIFY that the comparator is invoked at least 3 times
+ verify(comparator, atLeast(3)).compare(any(), any());
+
+ // VERIFY that the comparator is never invoked with the entry from package 0 or 3.
+ final NotificationEntry package0Entry = mEntrySet.get(0);
+ verify(comparator, never()).compare(eq(package0Entry), any());
+ verify(comparator, never()).compare(any(), eq(package0Entry));
+ final NotificationEntry package3Entry = mEntrySet.get(3);
+ verify(comparator, never()).compare(eq(package3Entry), any());
+ verify(comparator, never()).compare(any(), eq(package3Entry));
+ }
+
+ @Test
+ public void testThatSectionComparatorsAreNotCalledForSectionWithSingleEntry() {
+ // GIVEN a section with a comparator that will have only 1 element
+ NotifComparator comparator = spy(new HypeComparator(PACKAGE_3));
+ NotifSectioner sectioner = new PackageSectioner(List.of(PACKAGE_3), comparator);
+ mListBuilder.setSectioners(List.of(sectioner));
+
+ // WHEN the pipeline is kicked off on a bunch of notifications
+ addNotif(0, PACKAGE_1);
+ addNotif(1, PACKAGE_2);
+ addNotif(2, PACKAGE_3);
+ addNotif(3, PACKAGE_4);
+ addNotif(4, PACKAGE_5);
+ dispatchBuild();
+
+ // THEN the notifs are sorted according to the sectioning
+ verifyBuiltList(
+ notif(2),
+ notif(0),
+ notif(1),
+ notif(3),
+ notif(4)
+ );
+
+ // VERIFY that the comparator is never invoked
+ verify(comparator, never()).compare(any(), any());
+ }
+
+ @Test
public void testListenersAndPluggablesAreFiredInOrder() {
// GIVEN a bunch of registered listeners and pluggables
NotifFilter preGroupFilter = spy(new PackageFilter(PACKAGE_1));
@@ -934,7 +1003,8 @@ public class ShadeListBuilderTest extends SysuiTestCase {
// GIVEN a variety of pluggables
NotifFilter packageFilter = new PackageFilter(PACKAGE_1);
NotifPromoter idPromoter = new IdPromoter(4);
- NotifSectioner section = new PackageSectioner(PACKAGE_1);
+ NotifComparator sectionComparator = new HypeComparator(PACKAGE_1);
+ NotifSectioner section = new PackageSectioner(List.of(PACKAGE_1), sectionComparator);
NotifComparator hypeComparator = new HypeComparator(PACKAGE_2);
Invalidator preRenderInvalidator = new Invalidator("PreRenderInvalidator") {};
@@ -969,6 +1039,10 @@ public class ShadeListBuilderTest extends SysuiTestCase {
verify(mOnRenderListListener).onRenderList(anyList());
clearInvocations(mOnRenderListListener);
+ sectionComparator.invalidateList();
+ verify(mOnRenderListListener).onRenderList(anyList());
+
+ clearInvocations(mOnRenderListListener);
preRenderInvalidator.invalidateList();
verify(mOnRenderListListener).onRenderList(anyList());
}
@@ -2037,16 +2111,30 @@ public class ShadeListBuilderTest extends SysuiTestCase {
/** Represents a section for the passed pkg */
private static class PackageSectioner extends NotifSectioner {
- private final String mPackage;
+ private final List<String> mPackages;
+ private final NotifComparator mComparator;
+
+ PackageSectioner(List<String> pkgs, NotifComparator comparator) {
+ super("PackageSection_" + pkgs, 0);
+ mPackages = pkgs;
+ mComparator = comparator;
+ }
PackageSectioner(String pkg) {
super("PackageSection_" + pkg, 0);
- mPackage = pkg;
+ mPackages = List.of(pkg);
+ mComparator = null;
+ }
+
+ @Nullable
+ @Override
+ public NotifComparator getComparator() {
+ return mComparator;
}
@Override
public boolean isInSection(ListEntry entry) {
- return entry.getRepresentativeEntry().getSbn().getPackageName().equals(mPackage);
+ return mPackages.contains(entry.getRepresentativeEntry().getSbn().getPackageName());
}
}
@@ -2157,6 +2245,7 @@ public class ShadeListBuilderTest extends SysuiTestCase {
}
}
+ private static final String PACKAGE_0 = "com.test0";
private static final String PACKAGE_1 = "com.test1";
private static final String PACKAGE_2 = "com.test2";
private static final String PACKAGE_3 = "org.test3";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
index 8deac94214bd..7692a05eb5fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/ConversationCoordinatorTest.kt
@@ -32,7 +32,6 @@ import com.android.systemui.statusbar.notification.collection.render.NodeControl
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_IMPORTANT_PERSON
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier.Companion.TYPE_PERSON
-import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertFalse
@@ -41,7 +40,6 @@ import org.junit.Before
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
import org.mockito.Mockito.`when` as whenever
@@ -79,7 +77,7 @@ class ConversationCoordinatorTest : SysuiTestCase() {
}
peopleSectioner = coordinator.sectioner
- peopleComparator = coordinator.comparator
+ peopleComparator = peopleSectioner.comparator!!
entry = NotificationEntryBuilder().setChannel(channel).build()
@@ -108,16 +106,6 @@ class ConversationCoordinatorTest : SysuiTestCase() {
}
@Test
- fun testComparatorIgnoresFromOtherSection() {
- val e1 = NotificationEntryBuilder().setId(1).setChannel(channel).build()
- val e2 = NotificationEntryBuilder().setId(2).setChannel(channel).build()
-
- // wrong section -- never classify
- assertThat(peopleComparator.compare(e1, e2)).isEqualTo(0)
- verify(peopleNotificationIdentifier, never()).getPeopleNotificationType(any())
- }
-
- @Test
fun testComparatorPutsImportantPeopleFirst() {
whenever(peopleNotificationIdentifier.getPeopleNotificationType(entryA))
.thenReturn(TYPE_IMPORTANT_PERSON)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index bdcbbbc99ea3..4f731ed5f72c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.stack;
-import static android.provider.Settings.Secure.NOTIFICATION_HISTORY_ENABLED;
import static android.view.View.GONE;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
@@ -41,8 +40,6 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.os.UserHandle;
-import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.MathUtils;
@@ -112,10 +109,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
public void setUp() throws Exception {
allowTestableLooperAsMainThread();
- Settings.Secure.putIntForUser(mContext.getContentResolver(), NOTIFICATION_HISTORY_ENABLED,
- 1, UserHandle.USER_CURRENT);
-
-
// Interact with real instance of AmbientState.
mAmbientState = new AmbientState(mContext, mNotificationSectionsManager, mBypassController);
@@ -150,6 +143,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mStackScroller.setShelfController(notificationShelfController);
mStackScroller.setStatusBar(mBar);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
+ when(mStackScrollLayoutController.isHistoryEnabled()).thenReturn(true);
when(mStackScrollLayoutController.getNoticationRoundessManager())
.thenReturn(mNotificationRoundnessManager);
mStackScroller.setController(mStackScrollLayoutController);
@@ -404,6 +398,22 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
}
@Test
+ public void testUpdateFooter_withoutHistory() {
+ setBarStateForTest(StatusBarState.SHADE);
+ mStackScroller.setCurrentUserSetup(true);
+
+ when(mStackScrollLayoutController.isHistoryEnabled()).thenReturn(false);
+ when(mStackScrollLayoutController.getVisibleNotificationCount()).thenReturn(1);
+ when(mStackScrollLayoutController.hasActiveClearableNotifications(eq(ROWS_ALL)))
+ .thenReturn(true);
+
+ FooterView view = mock(FooterView.class);
+ mStackScroller.setFooterView(view);
+ mStackScroller.updateFooter();
+ verify(mStackScroller).updateFooterView(true, true, false);
+ }
+
+ @Test
public void testUpdateFooter_oneClearableNotification_beforeUserSetup() {
setBarStateForTest(StatusBarState.SHADE);
mStackScroller.setCurrentUserSetup(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index d3258408b33a..424a40058997 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -128,6 +128,28 @@ public class HeadsUpManagerTest extends AlertingNotificationManagerTest {
}
@Test
+ public void testCompareTo_withNullEntries() {
+ NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();
+ mHeadsUpManager.showNotification(alertEntry);
+
+ assertThat(mHeadsUpManager.compare(alertEntry, null)).isLessThan(0);
+ assertThat(mHeadsUpManager.compare(null, alertEntry)).isGreaterThan(0);
+ assertThat(mHeadsUpManager.compare(null, null)).isEqualTo(0);
+ }
+
+ @Test
+ public void testCompareTo_withNonAlertEntries() {
+ NotificationEntry nonAlertEntry1 = new NotificationEntryBuilder().setTag("nae1").build();
+ NotificationEntry nonAlertEntry2 = new NotificationEntryBuilder().setTag("nae2").build();
+ NotificationEntry alertEntry = new NotificationEntryBuilder().setTag("alert").build();
+ mHeadsUpManager.showNotification(alertEntry);
+
+ assertThat(mHeadsUpManager.compare(alertEntry, nonAlertEntry1)).isLessThan(0);
+ assertThat(mHeadsUpManager.compare(nonAlertEntry1, alertEntry)).isGreaterThan(0);
+ assertThat(mHeadsUpManager.compare(nonAlertEntry1, nonAlertEntry2)).isEqualTo(0);
+ }
+
+ @Test
public void testAlertEntryCompareTo_ongoingCallLessThanActiveRemoteInput() {
HeadsUpManager.HeadsUpEntry ongoingCall = mHeadsUpManager.new HeadsUpEntry();
ongoingCall.setEntry(new NotificationEntryBuilder()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
new file mode 100644
index 000000000000..ac357ea34be0
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/drawable/DrawableSizeTest.kt
@@ -0,0 +1,73 @@
+package com.android.systemui.util.drawable
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ShapeDrawable
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class DrawableSizeTest : SysuiTestCase() {
+
+ lateinit var resources: Resources
+
+ @Before
+ fun setUp() {
+ resources = context.resources
+ }
+
+ @Test
+ fun testDownscaleToSize_drawableZeroSize_unchanged() {
+ val drawable = ShapeDrawable()
+ val result = DrawableSize.downscaleToSize(resources, drawable, 100, 100)
+ assertThat(result).isSameInstanceAs(drawable)
+ }
+
+ @Test
+ fun testDownscaleToSize_drawableSmallerThanRequirement_unchanged() {
+ val drawable = BitmapDrawable(resources,
+ Bitmap.createBitmap(
+ resources.displayMetrics,
+ 150,
+ 150,
+ Bitmap.Config.ARGB_8888
+ )
+ )
+ val result = DrawableSize.downscaleToSize(resources, drawable, 300, 300)
+ assertThat(result).isSameInstanceAs(drawable)
+ }
+
+ @Test
+ fun testDownscaleToSize_drawableLargerThanRequirementWithDensity_resized() {
+ // This bitmap would actually fail to resize if the method doesn't check for
+ // bitmap dimensions inside drawable.
+ val drawable = BitmapDrawable(resources,
+ Bitmap.createBitmap(
+ resources.displayMetrics,
+ 150,
+ 75,
+ Bitmap.Config.ARGB_8888
+ )
+ )
+
+ val result = DrawableSize.downscaleToSize(resources, drawable, 75, 75)
+ assertThat(result).isNotSameInstanceAs(drawable)
+ assertThat(result.intrinsicWidth).isEqualTo(75)
+ assertThat(result.intrinsicHeight).isEqualTo(37)
+ }
+
+ @Test
+ fun testDownscaleToSize_drawableAnimated_unchanged() {
+ val drawable = resources.getDrawable(android.R.drawable.stat_sys_download,
+ resources.newTheme())
+ val result = DrawableSize.downscaleToSize(resources, drawable, 1, 1)
+ assertThat(result).isSameInstanceAs(drawable)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 9c49e98b9e36..ca37a40474e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -1339,6 +1339,22 @@ public class BubblesTest extends SysuiTestCase {
assertThat(mBubbleData.hasOverflowBubbleWithKey(entry.getKey())).isFalse();
}
+ @Test
+ public void testStackViewOnBackPressed_updatesBubbleDataExpandState() {
+ mBubbleController.updateBubble(mBubbleEntry);
+
+ // Expand the stack
+ mBubbleData.setExpanded(true);
+ assertStackExpanded();
+
+ // Hit back
+ BubbleStackView stackView = mBubbleController.getStackView();
+ stackView.onBackPressed();
+
+ // Make sure we're collapsed
+ assertStackCollapsed();
+ }
+
/** Creates a bubble using the userId and package. */
private Bubble createBubble(int userId, String pkg) {
final UserHandle userHandle = new UserHandle(userId);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
index e12a82a1c62b..d82671d6ecb8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/NewNotifPipelineBubblesTest.java
@@ -1158,6 +1158,22 @@ public class NewNotifPipelineBubblesTest extends SysuiTestCase {
assertThat(mBubbleData.hasOverflowBubbleWithKey(entry.getKey())).isFalse();
}
+ @Test
+ public void testStackViewOnBackPressed_updatesBubbleDataExpandState() {
+ mBubbleController.updateBubble(mBubbleEntry);
+
+ // Expand the stack
+ mBubbleData.setExpanded(true);
+ assertStackExpanded();
+
+ // Hit back
+ BubbleStackView stackView = mBubbleController.getStackView();
+ stackView.onBackPressed();
+
+ // Make sure we're collapsed
+ assertStackCollapsed();
+ }
+
/**
* Sets the bubble metadata flags for this entry. These flags are normally set by
* NotificationManagerService when the notification is sent, however, these tests do not
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index e93ac47b1940..8b62a64f57d4 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -66,6 +66,7 @@ import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -269,6 +270,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
void onDoubleTap(int displayId);
void onDoubleTapAndHold(int displayId);
+
}
public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
@@ -2164,4 +2166,23 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
public void onDoubleTapAndHold(int displayId) {
mSystemSupport.onDoubleTapAndHold(displayId);
}
-}
+
+ /**
+ * Sets the scaling factor for animations.
+ */
+ public void setAnimationScale(float scale) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Global.putFloat(
+ mContext.getContentResolver(), Settings.Global.WINDOW_ANIMATION_SCALE, scale);
+ Settings.Global.putFloat(
+ mContext.getContentResolver(),
+ Settings.Global.TRANSITION_ANIMATION_SCALE,
+ scale);
+ Settings.Global.putFloat(
+ mContext.getContentResolver(), Settings.Global.ANIMATOR_DURATION_SCALE, scale);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+} \ No newline at end of file
diff --git a/services/companion/TEST_MAPPING b/services/companion/TEST_MAPPING
index 63f54fa35158..4a37cb812981 100644
--- a/services/companion/TEST_MAPPING
+++ b/services/companion/TEST_MAPPING
@@ -1,6 +1,12 @@
{
"presubmit": [
{
+ "name": "CtsCompanionDeviceManagerCoreTestCases"
+ },
+ {
+ "name": "CtsCompanionDeviceManagerUiAutomationTestCases"
+ },
+ {
"name": "CtsOsTestCases",
"options": [
{
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index bb49ba059d23..75acf81a4a3c 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -39,7 +39,6 @@ import android.window.DisplayWindowPolicyController;
import java.util.List;
import java.util.Set;
-import java.util.function.Consumer;
/**
@@ -62,7 +61,6 @@ class GenericWindowPolicyController extends DisplayWindowPolicyController {
private final ArraySet<ComponentName> mAllowedActivities;
@Nullable
private final ArraySet<ComponentName> mBlockedActivities;
- private Consumer<ActivityInfo> mActivityBlockedCallback;
@NonNull
final ArraySet<Integer> mRunningUids = new ArraySet<>();
@@ -83,12 +81,10 @@ class GenericWindowPolicyController extends DisplayWindowPolicyController {
@NonNull ArraySet<UserHandle> allowedUsers,
@Nullable Set<ComponentName> allowedActivities,
@Nullable Set<ComponentName> blockedActivities,
- @NonNull ActivityListener activityListener,
- @NonNull Consumer<ActivityInfo> activityBlockedCallback) {
+ @NonNull ActivityListener activityListener) {
mAllowedUsers = allowedUsers;
mAllowedActivities = allowedActivities == null ? null : new ArraySet<>(allowedActivities);
mBlockedActivities = blockedActivities == null ? null : new ArraySet<>(blockedActivities);
- mActivityBlockedCallback = activityBlockedCallback;
setInterestedWindowFlags(windowFlags, systemWindowFlags);
mActivityListener = activityListener;
}
@@ -100,7 +96,6 @@ class GenericWindowPolicyController extends DisplayWindowPolicyController {
for (int i = 0; i < activityCount; i++) {
final ActivityInfo aInfo = activities.get(i);
if (!canContainActivity(aInfo, /* windowFlags= */ 0, /* systemWindowFlags= */ 0)) {
- mActivityBlockedCallback.accept(aInfo);
return false;
}
}
@@ -110,11 +105,7 @@ class GenericWindowPolicyController extends DisplayWindowPolicyController {
@Override
public boolean keepActivityOnWindowFlagsChanged(ActivityInfo activityInfo, int windowFlags,
int systemWindowFlags) {
- if (!canContainActivity(activityInfo, windowFlags, systemWindowFlags)) {
- mActivityBlockedCallback.accept(activityInfo);
- return false;
- }
- return true;
+ return canContainActivity(activityInfo, windowFlags, systemWindowFlags);
}
@Override
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 98a5ec1c3681..95b9e58a9dfd 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -34,8 +34,6 @@ import android.companion.virtual.VirtualDeviceManager.ActivityListener;
import android.companion.virtual.VirtualDeviceParams;
import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.display.DisplayManager;
@@ -59,7 +57,6 @@ import android.util.SparseArray;
import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.BlockedAppActivity;
import com.android.server.LocalServices;
import java.io.FileDescriptor;
@@ -421,8 +418,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
getAllowedUserHandles(),
mParams.getAllowedActivities(),
mParams.getBlockedActivities(),
- createListenerAdapter(displayId),
- activityInfo -> onActivityBlocked(displayId, activityInfo));
+ createListenerAdapter(displayId));
mWindowPolicyControllers.put(displayId, dwpc);
return dwpc;
}
@@ -445,16 +441,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
}
}
- private void onActivityBlocked(int displayId, ActivityInfo activityInfo) {
- Intent intent = BlockedAppActivity.createStreamingBlockedIntent(
- UserHandle.getUserId(activityInfo.applicationInfo.uid), activityInfo,
- mAssociationInfo.getDisplayName());
- mContext.startActivityAsUser(
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
- ActivityOptions.makeBasic().setLaunchDisplayId(displayId).toBundle(),
- mContext.getUser());
- }
-
private ArraySet<UserHandle> getAllowedUserHandles() {
ArraySet<UserHandle> result = new ArraySet<>();
DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index ce30f0348f11..d719d77ea1be 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -509,8 +509,7 @@ public final class SystemServiceManager implements Dumpable {
throw new IllegalArgumentException(onWhat + " what?");
}
} catch (Exception ex) {
- Slog.wtf(TAG, "Failure reporting " + onWhat + " of user " + curUser
- + " to service " + serviceName, ex);
+ logFailure(onWhat, curUser, serviceName, ex);
}
if (!submitToThreadPool) {
warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
@@ -584,8 +583,7 @@ public final class SystemServiceManager implements Dumpable {
warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
"on" + USER_STARTING + "User-" + curUserId);
} catch (Exception e) {
- Slog.wtf(TAG, "Failure reporting " + USER_STARTING + " of user " + curUser
- + " to service " + serviceName, e);
+ logFailure(USER_STARTING, curUser, serviceName, e);
Slog.e(TAG, "Disabling thread pool - please capture a bug report.");
sUseLifecycleThreadPool = false;
} finally {
@@ -608,8 +606,7 @@ public final class SystemServiceManager implements Dumpable {
warnIfTooLong(SystemClock.elapsedRealtime() - time, service,
"on" + USER_COMPLETED_EVENT + "User-" + curUserId);
} catch (Exception e) {
- Slog.wtf(TAG, "Failure reporting " + USER_COMPLETED_EVENT + " of user " + curUser
- + " to service " + serviceName, e);
+ logFailure(USER_COMPLETED_EVENT, curUser, serviceName, e);
throw e;
} finally {
t.traceEnd();
@@ -617,6 +614,12 @@ public final class SystemServiceManager implements Dumpable {
};
}
+ /** Logs the failure. That's all. Tests may rely on parsing it, so only modify carefully. */
+ private void logFailure(String onWhat, TargetUser curUser, String serviceName, Exception ex) {
+ Slog.wtf(TAG, "SystemService failure: Failure reporting " + onWhat + " of user "
+ + curUser + " to service " + serviceName, ex);
+ }
+
/** Sets the safe mode flag for services to query. */
void setSafeMode(boolean safeMode) {
mSafeMode = safeMode;
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 6a7afd90dc96..2d328d8b0949 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -539,7 +539,13 @@ public class VcnManagementService extends IVcnManagementService.Stub {
@GuardedBy("mLock")
private void notifyAllPolicyListenersLocked() {
for (final PolicyListenerBinderDeath policyListener : mRegisteredPolicyListeners.values()) {
- Binder.withCleanCallingIdentity(() -> policyListener.mListener.onPolicyChanged());
+ Binder.withCleanCallingIdentity(() -> {
+ try {
+ policyListener.mListener.onPolicyChanged();
+ } catch (RemoteException e) {
+ logDbg("VcnStatusCallback threw on VCN status change", e);
+ }
+ });
}
}
@@ -548,8 +554,13 @@ public class VcnManagementService extends IVcnManagementService.Stub {
@NonNull ParcelUuid subGroup, @VcnStatusCode int statusCode) {
for (final VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
if (isCallbackPermissioned(cbInfo, subGroup)) {
- Binder.withCleanCallingIdentity(
- () -> cbInfo.mCallback.onVcnStatusChanged(statusCode));
+ Binder.withCleanCallingIdentity(() -> {
+ try {
+ cbInfo.mCallback.onVcnStatusChanged(statusCode);
+ } catch (RemoteException e) {
+ logDbg("VcnStatusCallback threw on VCN status change", e);
+ }
+ });
}
}
}
@@ -1222,13 +1233,17 @@ public class VcnManagementService extends IVcnManagementService.Stub {
// Notify all registered StatusCallbacks for this subGroup
for (VcnStatusCallbackInfo cbInfo : mRegisteredStatusCallbacks.values()) {
if (isCallbackPermissioned(cbInfo, mSubGroup)) {
- Binder.withCleanCallingIdentity(
- () ->
- cbInfo.mCallback.onGatewayConnectionError(
- gatewayConnectionName,
- errorCode,
- exceptionClass,
- exceptionMessage));
+ Binder.withCleanCallingIdentity(() -> {
+ try {
+ cbInfo.mCallback.onGatewayConnectionError(
+ gatewayConnectionName,
+ errorCode,
+ exceptionClass,
+ exceptionMessage);
+ } catch (RemoteException e) {
+ logDbg("VcnStatusCallback threw on VCN status change", e);
+ }
+ });
}
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index fafe908564ef..e2204e2efaca 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -459,7 +459,7 @@ public class ActivityManagerService extends IActivityManager.Stub
* broadcasts
*/
private static final boolean ENFORCE_DYNAMIC_RECEIVER_EXPLICIT_EXPORT =
- SystemProperties.getBoolean("fw.enforce_dynamic_receiver_explicit_export", true);
+ SystemProperties.getBoolean("fw.enforce_dynamic_receiver_explicit_export", false);
static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityManagerService" : TAG_AM;
static final String TAG_BACKUP = TAG + POSTFIX_BACKUP;
@@ -16089,6 +16089,23 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
+ * Returns package name by pid.
+ */
+ @Override
+ @Nullable
+ public String getPackageNameByPid(int pid) {
+ synchronized (mPidsSelfLocked) {
+ final ProcessRecord app = mPidsSelfLocked.get(pid);
+
+ if (app != null && app.info != null) {
+ return app.info.packageName;
+ }
+
+ return null;
+ }
+ }
+
+ /**
* Sets if the given pid has an overlay UI or not.
*
* @param pid The pid we are setting overlay UI for.
@@ -17888,6 +17905,11 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
+ @Override
+ public boolean isAppFreezerEnabled() {
+ return mOomAdjuster.mCachedAppOptimizer.useFreezer();
+ }
+
/**
* Resets the state of the {@link com.android.server.am.AppErrors} instance.
* This is intended for testing within the CTS only and is protected by
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 8561b61c2172..1131fa8a32b8 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -451,7 +451,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
mUidsToRemove.clear();
mCurrentFuture = null;
mUseLatestStates = true;
- if (updateFlags == UPDATE_ALL) {
+ if ((updateFlags & UPDATE_ALL) == UPDATE_ALL) {
cancelSyncDueToBatteryLevelChangeLocked();
}
if ((updateFlags & UPDATE_CPU) != 0) {
@@ -496,7 +496,11 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
Slog.wtf(TAG, "Error updating external stats: ", e);
}
- if ((updateFlags & UPDATE_ALL) == UPDATE_ALL) {
+ if ((updateFlags & RESET) != 0) {
+ synchronized (BatteryExternalStatsWorker.this) {
+ mLastCollectionTimeStamp = 0;
+ }
+ } else if ((updateFlags & UPDATE_ALL) == UPDATE_ALL) {
synchronized (BatteryExternalStatsWorker.this) {
mLastCollectionTimeStamp = SystemClock.elapsedRealtime();
}
@@ -658,7 +662,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
mStats.updateCpuTimeLocked(onBattery, onBatteryScreenOff, cpuClusterChargeUC);
}
- if (updateFlags == UPDATE_ALL) {
+ if ((updateFlags & UPDATE_ALL) == UPDATE_ALL) {
mStats.updateKernelWakelocksLocked(elapsedRealtimeUs);
mStats.updateKernelMemoryBandwidthLocked(elapsedRealtimeUs);
}
@@ -731,7 +735,7 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
uptime, networkStatsManager);
}
- if (updateFlags == UPDATE_ALL) {
+ if ((updateFlags & UPDATE_ALL) == UPDATE_ALL) {
// This helps mStats deal with ignoring data from prior to resets.
mStats.informThatAllExternalStatsAreFlushed();
}
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 5da461d8e392..2f7249ea5d84 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -797,12 +797,19 @@ public final class BatteryStatsService extends IBatteryStats.Stub
final BatteryUsageStats bus;
switch (atomTag) {
case FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET:
- bus = getBatteryUsageStats(List.of(BatteryUsageStatsQuery.DEFAULT)).get(0);
+ final BatteryUsageStatsQuery querySinceReset =
+ new BatteryUsageStatsQuery.Builder()
+ .includeProcessStateData()
+ .build();
+ bus = getBatteryUsageStats(List.of(querySinceReset)).get(0);
break;
case FrameworkStatsLog.BATTERY_USAGE_STATS_SINCE_RESET_USING_POWER_PROFILE_MODEL:
- final BatteryUsageStatsQuery powerProfileQuery =
- new BatteryUsageStatsQuery.Builder().powerProfileModeledOnly().build();
- bus = getBatteryUsageStats(List.of(powerProfileQuery)).get(0);
+ final BatteryUsageStatsQuery queryPowerProfile =
+ new BatteryUsageStatsQuery.Builder()
+ .includeProcessStateData()
+ .powerProfileModeledOnly()
+ .build();
+ bus = getBatteryUsageStats(List.of(queryPowerProfile)).get(0);
break;
case FrameworkStatsLog.BATTERY_USAGE_STATS_BEFORE_RESET:
if (!BATTERY_USAGE_STORE_ENABLED) {
@@ -812,10 +819,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub
final long sessionStart = mBatteryUsageStatsStore
.getLastBatteryUsageStatsBeforeResetAtomPullTimestamp();
final long sessionEnd = mStats.getStartClockTime();
- final BatteryUsageStatsQuery query = new BatteryUsageStatsQuery.Builder()
- .aggregateSnapshots(sessionStart, sessionEnd)
- .build();
- bus = getBatteryUsageStats(List.of(query)).get(0);
+ final BatteryUsageStatsQuery queryBeforeReset =
+ new BatteryUsageStatsQuery.Builder()
+ .includeProcessStateData()
+ .aggregateSnapshots(sessionStart, sessionEnd)
+ .build();
+ bus = getBatteryUsageStats(List.of(queryBeforeReset)).get(0);
mBatteryUsageStatsStore
.setLastBatteryUsageStatsBeforeResetAtomPullTimestamp(sessionEnd);
break;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 8ad62605098c..a83fdd0e74cd 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -56,6 +56,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PowerExemptionManager;
import android.os.PowerExemptionManager.ReasonCode;
import android.os.PowerExemptionManager.TempAllowListType;
import android.os.Process;
@@ -1857,22 +1858,36 @@ public final class BroadcastQueue {
}
private void maybeReportBroadcastDispatchedEventLocked(BroadcastRecord r, int targetUid) {
- final String targetPackage = getTargetPackage(r);
- // Ignore non-explicit broadcasts
- if (targetPackage == null) {
- return;
- }
// TODO (206518114): Only allow apps with ACCESS_PACKAGE_USAGE_STATS to set
// getIdForResponseEvent.
+ // TODO (217251579): Temporarily use temp-allowlist reason to identify
+ // push messages and record response events.
+ useTemporaryAllowlistReasonAsSignal(r);
if (r.options == null || r.options.getIdForResponseEvent() <= 0) {
return;
}
+ final String targetPackage = getTargetPackage(r);
+ // Ignore non-explicit broadcasts
+ if (targetPackage == null) {
+ return;
+ }
getUsageStatsManagerInternal().reportBroadcastDispatched(
r.callingUid, targetPackage, UserHandle.of(r.userId),
r.options.getIdForResponseEvent(), SystemClock.elapsedRealtime(),
mService.getUidStateLocked(targetUid));
}
+ private void useTemporaryAllowlistReasonAsSignal(BroadcastRecord r) {
+ if (r.options == null || r.options.getIdForResponseEvent() > 0) {
+ return;
+ }
+ final int reasonCode = r.options.getTemporaryAppAllowlistReasonCode();
+ if (reasonCode == PowerExemptionManager.REASON_PUSH_MESSAGING
+ || reasonCode == PowerExemptionManager.REASON_PUSH_MESSAGING_OVER_QUOTA) {
+ r.options.recordResponseEventWhileInBackground(reasonCode);
+ }
+ }
+
@NonNull
private UsageStatsManagerInternal getUsageStatsManagerInternal() {
final UsageStatsManagerInternal usageStatsManagerInternal =
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 6f22c61d2b2a..7af73ebda0c0 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -977,7 +977,7 @@ public final class CachedAppOptimizer {
Slog.d(TAG_AM, "pid " + pid + " " + app.processName
+ " received sync transactions while frozen, killing");
app.killLocked("Sync transaction while in frozen state",
- ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.REASON_FREEZER,
ApplicationExitInfo.SUBREASON_FREEZER_BINDER_TRANSACTION, true);
processKilled = true;
}
@@ -990,7 +990,7 @@ public final class CachedAppOptimizer {
Slog.d(TAG_AM, "Unable to query binder frozen info for pid " + pid + " "
+ app.processName + ". Killing it. Exception: " + e);
app.killLocked("Unable to query binder frozen stats",
- ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.REASON_FREEZER,
ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
processKilled = true;
}
@@ -1007,7 +1007,7 @@ public final class CachedAppOptimizer {
Slog.e(TAG_AM, "Unable to unfreeze binder for " + pid + " " + app.processName
+ ". Killing it");
app.killLocked("Unable to unfreeze",
- ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.REASON_FREEZER,
ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
return;
}
@@ -1423,7 +1423,7 @@ public final class CachedAppOptimizer {
mFreezeHandler.post(() -> {
synchronized (mAm) {
proc.killLocked("Unable to freeze binder interface",
- ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.REASON_FREEZER,
ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
}
});
@@ -1477,7 +1477,7 @@ public final class CachedAppOptimizer {
mFreezeHandler.post(() -> {
synchronized (mAm) {
proc.killLocked("Unable to freeze binder interface",
- ApplicationExitInfo.REASON_OTHER,
+ ApplicationExitInfo.REASON_FREEZER,
ApplicationExitInfo.SUBREASON_FREEZER_BINDER_IOCTL, true);
}
});
diff --git a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
index 960fbf1d9330..145a298af95e 100644
--- a/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
+++ b/services/core/java/com/android/server/app/GameServiceProviderInstanceImpl.java
@@ -43,6 +43,7 @@ import android.service.games.IGameSession;
import android.service.games.IGameSessionController;
import android.service.games.IGameSessionService;
import android.util.Slog;
+import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost.SurfacePackage;
import com.android.internal.annotations.GuardedBy;
@@ -237,7 +238,7 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
mTaskSystemBarsVisibilityListener);
for (GameSessionRecord gameSessionRecord : mGameSessions.values()) {
- destroyGameSessionFromRecord(gameSessionRecord);
+ destroyGameSessionFromRecordLocked(gameSessionRecord);
}
mGameSessions.clear();
@@ -510,10 +511,11 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
}
return;
}
- destroyGameSessionFromRecord(gameSessionRecord);
+ destroyGameSessionFromRecordLocked(gameSessionRecord);
}
- private void destroyGameSessionFromRecord(@NonNull GameSessionRecord gameSessionRecord) {
+ @GuardedBy("mLock")
+ private void destroyGameSessionFromRecordLocked(@NonNull GameSessionRecord gameSessionRecord) {
SurfacePackage surfacePackage = gameSessionRecord.getSurfacePackage();
if (surfacePackage != null) {
try {
@@ -586,17 +588,29 @@ final class GameServiceProviderInstanceImpl implements GameServiceProviderInstan
@VisibleForTesting
void takeScreenshot(int taskId, @NonNull AndroidFuture callback) {
+ GameSessionRecord gameSessionRecord;
synchronized (mLock) {
- boolean isTaskAssociatedWithGameSession = mGameSessions.containsKey(taskId);
- if (!isTaskAssociatedWithGameSession) {
+ gameSessionRecord = mGameSessions.get(taskId);
+ if (gameSessionRecord == null) {
Slog.w(TAG, "No game session found for id: " + taskId);
callback.complete(GameScreenshotResult.createInternalErrorResult());
return;
}
}
+ final SurfacePackage overlaySurfacePackage = gameSessionRecord.getSurfacePackage();
+ final SurfaceControl overlaySurfaceControl =
+ overlaySurfacePackage != null ? overlaySurfacePackage.getSurfaceControl() : null;
mBackgroundExecutor.execute(() -> {
- final Bitmap bitmap = mWindowManagerService.captureTaskBitmap(taskId);
+ final SurfaceControl.LayerCaptureArgs.Builder layerCaptureArgsBuilder =
+ new SurfaceControl.LayerCaptureArgs.Builder(/* layer */ null);
+ if (overlaySurfaceControl != null) {
+ SurfaceControl[] excludeLayers = new SurfaceControl[1];
+ excludeLayers[0] = overlaySurfaceControl;
+ layerCaptureArgsBuilder.setExcludeLayers(excludeLayers);
+ }
+ final Bitmap bitmap = mWindowManagerService.captureTaskBitmap(taskId,
+ layerCaptureArgsBuilder);
if (bitmap == null) {
Slog.w(TAG, "Could not get bitmap for id: " + taskId);
callback.complete(GameScreenshotResult.createInternalErrorResult());
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 65be5f06d08f..daf3561d75ce 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -29,7 +29,7 @@ import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
-import android.media.BtProfileConnectionInfo;
+import android.media.BluetoothProfileConnectionInfo;
import android.media.IAudioRoutesObserver;
import android.media.ICapturePresetDevicesRoleDispatcher;
import android.media.ICommunicationDeviceDispatcher;
@@ -500,12 +500,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
- /*package*/ void setWiredDeviceConnectionState(int type,
- @AudioService.ConnectionState int state, String address, String name,
- String caller) {
+ /*package*/ void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
+ @AudioService.ConnectionState int state, String caller) {
//TODO move logging here just like in setBluetooth* methods
synchronized (mDeviceStateLock) {
- mDeviceInventory.setWiredDeviceConnectionState(type, state, address, name, caller);
+ mDeviceInventory.setWiredDeviceConnectionState(attributes, state, caller);
}
}
@@ -531,12 +530,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
/*package*/ static final class BtDeviceChangedData {
final @Nullable BluetoothDevice mNewDevice;
final @Nullable BluetoothDevice mPreviousDevice;
- final @NonNull BtProfileConnectionInfo mInfo;
+ final @NonNull BluetoothProfileConnectionInfo mInfo;
final @NonNull String mEventSource;
BtDeviceChangedData(@Nullable BluetoothDevice newDevice,
@Nullable BluetoothDevice previousDevice,
- @NonNull BtProfileConnectionInfo info, @NonNull String eventSource) {
+ @NonNull BluetoothProfileConnectionInfo info, @NonNull String eventSource) {
mNewDevice = newDevice;
mPreviousDevice = previousDevice;
mInfo = info;
@@ -568,9 +567,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
mDevice = device;
mState = state;
mProfile = d.mInfo.getProfile();
- mSupprNoisy = d.mInfo.getSuppressNoisyIntent();
+ mSupprNoisy = d.mInfo.isSuppressNoisyIntent();
mVolume = d.mInfo.getVolume();
- mIsLeOutput = d.mInfo.getIsLeOutput();
+ mIsLeOutput = d.mInfo.isLeOutput();
mEventSource = d.mEventSource;
mAudioSystemDevice = audioDevice;
mMusicDevice = AudioSystem.DEVICE_NONE;
@@ -641,7 +640,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
audioDevice = AudioSystem.DEVICE_OUT_HEARING_AID;
break;
case BluetoothProfile.LE_AUDIO:
- if (d.mInfo.getIsLeOutput()) {
+ if (d.mInfo.isLeOutput()) {
audioDevice = AudioSystem.DEVICE_OUT_BLE_HEADSET;
} else {
audioDevice = AudioSystem.DEVICE_IN_BLE_HEADSET;
@@ -1013,11 +1012,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
}
}
- /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
- String deviceName) {
+ /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect) {
synchronized (mDeviceStateLock) {
- return mDeviceInventory.handleDeviceConnection(connect, device, address, deviceName,
- false /*for test*/);
+ return mDeviceInventory.handleDeviceConnection(attributes, connect, false /*for test*/);
}
}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 4ae1bd371690..0e290410d288 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -230,19 +230,15 @@ public class AudioDeviceInventory {
* A class just for packaging up a set of connection parameters.
*/
/*package*/ class WiredDeviceConnectionState {
- public final int mType;
+ public final AudioDeviceAttributes mAttributes;
public final @AudioService.ConnectionState int mState;
- public final String mAddress;
- public final String mName;
public final String mCaller;
public boolean mForTest = false;
- /*package*/ WiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
- String address, String name, String caller) {
- mType = type;
+ /*package*/ WiredDeviceConnectionState(AudioDeviceAttributes attributes,
+ @AudioService.ConnectionState int state, String caller) {
+ mAttributes = attributes;
mState = state;
- mAddress = address;
- mName = name;
mCaller = caller;
}
}
@@ -280,11 +276,10 @@ public class AudioDeviceInventory {
synchronized (mDevicesLock) {
//TODO iterate on mApmConnectedDevices instead once it handles all device types
for (DeviceInfo di : mConnectedDevices.values()) {
- mAudioSystem.setDeviceConnectionState(
- di.mDeviceType,
- AudioSystem.DEVICE_STATE_AVAILABLE,
+ mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(di.mDeviceType,
di.mDeviceAddress,
- di.mDeviceName,
+ di.mDeviceName),
+ AudioSystem.DEVICE_STATE_AVAILABLE,
di.mDeviceCodecFormat);
}
}
@@ -519,41 +514,45 @@ public class AudioDeviceInventory {
/*package*/ void onSetWiredDeviceConnectionState(
AudioDeviceInventory.WiredDeviceConnectionState wdcs) {
+ int type = wdcs.mAttributes.getInternalType();
+
AudioService.sDeviceLogger.log(new AudioServiceEvents.WiredDevConnectEvent(wdcs));
MediaMetrics.Item mmi = new MediaMetrics.Item(mMetricsId
+ "onSetWiredDeviceConnectionState")
- .set(MediaMetrics.Property.ADDRESS, wdcs.mAddress)
- .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(wdcs.mType))
+ .set(MediaMetrics.Property.ADDRESS, wdcs.mAttributes.getAddress())
+ .set(MediaMetrics.Property.DEVICE,
+ AudioSystem.getDeviceName(type))
.set(MediaMetrics.Property.STATE,
wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED
? MediaMetrics.Value.DISCONNECTED : MediaMetrics.Value.CONNECTED);
synchronized (mDevicesLock) {
if ((wdcs.mState == AudioService.CONNECTION_STATE_DISCONNECTED)
- && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
+ && DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/,
"onSetWiredDeviceConnectionState state DISCONNECTED");
}
- if (!handleDeviceConnection(wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED,
- wdcs.mType, wdcs.mAddress, wdcs.mName, wdcs.mForTest)) {
+ if (!handleDeviceConnection(wdcs.mAttributes,
+ wdcs.mState == AudioService.CONNECTION_STATE_CONNECTED, wdcs.mForTest)) {
// change of connection state failed, bailout
mmi.set(MediaMetrics.Property.EARLY_RETURN, "change of connection state failed")
.record();
return;
}
if (wdcs.mState != AudioService.CONNECTION_STATE_DISCONNECTED) {
- if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(wdcs.mType)) {
+ if (DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG_SET.contains(type)) {
mDeviceBroker.setBluetoothA2dpOnInt(false, false /*fromA2dp*/,
"onSetWiredDeviceConnectionState state not DISCONNECTED");
}
- mDeviceBroker.checkMusicActive(wdcs.mType, wdcs.mCaller);
+ mDeviceBroker.checkMusicActive(type, wdcs.mCaller);
}
- if (wdcs.mType == AudioSystem.DEVICE_OUT_HDMI) {
+ if (type == AudioSystem.DEVICE_OUT_HDMI) {
mDeviceBroker.checkVolumeCecOnHdmiConnection(wdcs.mState, wdcs.mCaller);
}
- sendDeviceConnectionIntent(wdcs.mType, wdcs.mState, wdcs.mAddress, wdcs.mName);
- updateAudioRoutes(wdcs.mType, wdcs.mState);
+ sendDeviceConnectionIntent(type, wdcs.mState,
+ wdcs.mAttributes.getAddress(), wdcs.mAttributes.getName());
+ updateAudioRoutes(type, wdcs.mState);
}
mmi.record();
}
@@ -572,12 +571,12 @@ public class AudioDeviceInventory {
return;
}
// Toggle HDMI to retrigger broadcast with proper formats.
- setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
- AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
- "android"); // disconnect
- setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
- AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
- "android"); // reconnect
+ setWiredDeviceConnectionState(
+ new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, "android"); // disconnect
+ setWiredDeviceConnectionState(
+ new AudioDeviceAttributes(AudioSystem.DEVICE_OUT_HDMI, ""),
+ AudioSystem.DEVICE_STATE_AVAILABLE, "android"); // reconnect
}
mmi.record();
}
@@ -707,16 +706,17 @@ public class AudioDeviceInventory {
/**
* Implements the communication with AudioSystem to (dis)connect a device in the native layers
+ * @param attributes the attributes of the device
* @param connect true if connection
- * @param device the device type
- * @param address the address of the device
- * @param deviceName human-readable name of device
* @param isForTesting if true, not calling AudioSystem for the connection as this is
* just for testing
* @return false if an error was reported by AudioSystem
*/
- /*package*/ boolean handleDeviceConnection(boolean connect, int device, String address,
- String deviceName, boolean isForTesting) {
+ /*package*/ boolean handleDeviceConnection(AudioDeviceAttributes attributes, boolean connect,
+ boolean isForTesting) {
+ int device = attributes.getInternalType();
+ String address = attributes.getAddress();
+ String deviceName = attributes.getName();
if (AudioService.DEBUG_DEVICES) {
Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:"
+ Integer.toHexString(device) + " address:" + address
@@ -743,9 +743,8 @@ public class AudioDeviceInventory {
if (isForTesting) {
res = AudioSystem.AUDIO_STATUS_OK;
} else {
- res = mAudioSystem.setDeviceConnectionState(device,
- AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
+ res = mAudioSystem.setDeviceConnectionState(attributes,
+ AudioSystem.DEVICE_STATE_AVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
}
if (res != AudioSystem.AUDIO_STATUS_OK) {
final String reason = "not connecting device 0x" + Integer.toHexString(device)
@@ -762,9 +761,8 @@ public class AudioDeviceInventory {
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
return true;
} else if (!connect && isConnected) {
- mAudioSystem.setDeviceConnectionState(device,
- AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName,
- AudioSystem.AUDIO_FORMAT_DEFAULT);
+ mAudioSystem.setDeviceConnectionState(attributes,
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, AudioSystem.AUDIO_FORMAT_DEFAULT);
// always remove even if disconnection failed
mConnectedDevices.remove(deviceKey);
mmi.set(MediaMetrics.Property.STATE, MediaMetrics.Value.CONNECTED).record();
@@ -941,13 +939,13 @@ public class AudioDeviceInventory {
return delay;
}
- /*package*/ int setWiredDeviceConnectionState(int type, @AudioService.ConnectionState int state,
- String address, String name, String caller) {
+ /*package*/ int setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
+ @AudioService.ConnectionState int state, String caller) {
synchronized (mDevicesLock) {
- int delay = checkSendBecomingNoisyIntentInt(type, state, AudioSystem.DEVICE_NONE);
+ int delay = checkSendBecomingNoisyIntentInt(
+ attributes.getInternalType(), state, AudioSystem.DEVICE_NONE);
mDeviceBroker.postSetWiredDeviceConnectionState(
- new WiredDeviceConnectionState(type, state, address, name, caller),
- delay);
+ new WiredDeviceConnectionState(attributes, state, caller), delay);
return delay;
}
}
@@ -955,8 +953,7 @@ public class AudioDeviceInventory {
/*package*/ void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device,
@AudioService.ConnectionState int state) {
final WiredDeviceConnectionState connection = new WiredDeviceConnectionState(
- device.getInternalType(), state, device.getAddress(),
- "test device", "com.android.server.audio");
+ device, state, "com.android.server.audio");
connection.mForTest = true;
onSetWiredDeviceConnectionState(connection);
}
@@ -972,8 +969,9 @@ public class AudioDeviceInventory {
mDeviceBroker.setBluetoothA2dpOnInt(true, true /*fromA2dp*/, eventSource);
// at this point there could be another A2DP device already connected in APM, but it
// doesn't matter as this new one will overwrite the previous one
- final int res = mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- AudioSystem.DEVICE_STATE_AVAILABLE, address, name, a2dpCodec);
+ final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address, name),
+ AudioSystem.DEVICE_STATE_AVAILABLE, a2dpCodec);
// TODO: log in MediaMetrics once distinction between connection failure and
// double connection is made.
@@ -1035,8 +1033,9 @@ public class AudioDeviceInventory {
// device to remove was visible by APM, update APM
mDeviceBroker.clearAvrcpAbsoluteVolumeSupported();
- final int res = mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "", a2dpCodec);
+ final int res = mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
+ AudioSystem.DEVICE_STATE_UNAVAILABLE, a2dpCodec);
if (res != AudioSystem.AUDIO_STATUS_OK) {
AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
@@ -1074,8 +1073,9 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeA2dpSrcAvailable(String address) {
- mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
- AudioSystem.DEVICE_STATE_AVAILABLE, address, "",
+ mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+ AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+ AudioSystem.DEVICE_STATE_AVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
@@ -1085,8 +1085,9 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeA2dpSrcUnavailable(String address) {
- mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
- AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
+ mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+ AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.remove(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
@@ -1099,8 +1100,9 @@ public class AudioDeviceInventory {
AudioSystem.DEVICE_OUT_HEARING_AID);
mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, streamType);
- mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
- AudioSystem.DEVICE_STATE_AVAILABLE, address, name,
+ mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_HEARING_AID, address, name),
+ AudioSystem.DEVICE_STATE_AVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
@@ -1122,8 +1124,9 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeHearingAidDeviceUnavailable(String address) {
- mAudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
- AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "",
+ mAudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_HEARING_AID, address),
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.remove(
DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
@@ -1140,14 +1143,14 @@ public class AudioDeviceInventory {
private void makeLeAudioDeviceAvailable(String address, String name, int streamType, int device,
String eventSource) {
if (device != AudioSystem.DEVICE_NONE) {
-
/* Audio Policy sees Le Audio similar to A2DP. Let's make sure
* AUDIO_POLICY_FORCE_NO_BT_A2DP is not set
*/
mDeviceBroker.setBluetoothA2dpOnInt(true, false /*fromA2dp*/, eventSource);
- AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
- address, name, AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(device, address, name),
+ AudioSystem.DEVICE_STATE_AVAILABLE,
+ AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.put(DeviceInfo.makeDeviceListKey(device, address),
new DeviceInfo(device, name, address, AudioSystem.AUDIO_FORMAT_DEFAULT));
mDeviceBroker.postAccessoryPlugMediaUnmute(device);
@@ -1168,8 +1171,9 @@ public class AudioDeviceInventory {
@GuardedBy("mDevicesLock")
private void makeLeAudioDeviceUnavailable(String address, int device) {
if (device != AudioSystem.DEVICE_NONE) {
- AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
- address, "", AudioSystem.AUDIO_FORMAT_DEFAULT);
+ AudioSystem.setDeviceConnectionState(new AudioDeviceAttributes(device, address),
+ AudioSystem.DEVICE_STATE_UNAVAILABLE,
+ AudioSystem.AUDIO_FORMAT_DEFAULT);
mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 407d42ea510d..05955c3cab44 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -85,7 +85,7 @@ import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
-import android.media.BtProfileConnectionInfo;
+import android.media.BluetoothProfileConnectionInfo;
import android.media.IAudioFocusDispatcher;
import android.media.IAudioModeDispatcher;
import android.media.IAudioRoutesObserver;
@@ -6371,23 +6371,23 @@ public class AudioService extends IAudioService.Stub
/**
* see AudioManager.setWiredDeviceConnectionState()
*/
- public void setWiredDeviceConnectionState(int type,
- @ConnectionState int state, String address, String name,
- String caller) {
+ public void setWiredDeviceConnectionState(AudioDeviceAttributes attributes,
+ @ConnectionState int state, String caller) {
enforceModifyAudioRoutingPermission();
if (state != CONNECTION_STATE_CONNECTED
&& state != CONNECTION_STATE_DISCONNECTED) {
throw new IllegalArgumentException("Invalid state " + state);
}
new MediaMetrics.Item(mMetricsId + "setWiredDeviceConnectionState")
- .set(MediaMetrics.Property.ADDRESS, address)
+ .set(MediaMetrics.Property.ADDRESS, attributes.getAddress())
.set(MediaMetrics.Property.CLIENT_NAME, caller)
- .set(MediaMetrics.Property.DEVICE, AudioSystem.getDeviceName(type))
- .set(MediaMetrics.Property.NAME, name)
+ .set(MediaMetrics.Property.DEVICE,
+ AudioSystem.getDeviceName(attributes.getInternalType()))
+ .set(MediaMetrics.Property.NAME, attributes.getName())
.set(MediaMetrics.Property.STATE,
state == CONNECTION_STATE_CONNECTED ? "connected" : "disconnected")
.record();
- mDeviceBroker.setWiredDeviceConnectionState(type, state, address, name, caller);
+ mDeviceBroker.setWiredDeviceConnectionState(attributes, state, caller);
}
/** @see AudioManager#setTestDeviceConnectionState(AudioDeviceAttributes, boolean) */
@@ -6434,14 +6434,14 @@ public class AudioService extends IAudioService.Stub
* See AudioManager.handleBluetoothActiveDeviceChanged(...)
*/
public void handleBluetoothActiveDeviceChanged(BluetoothDevice newDevice,
- BluetoothDevice previousDevice, @NonNull BtProfileConnectionInfo info) {
+ BluetoothDevice previousDevice, @NonNull BluetoothProfileConnectionInfo info) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.BLUETOOTH_STACK)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Bluetooth is the only caller allowed");
}
if (info == null) {
- throw new IllegalArgumentException("Illegal null BtProfileConnectionInfo for device "
- + previousDevice + " -> " + newDevice);
+ throw new IllegalArgumentException("Illegal null BluetoothProfileConnectionInfo for"
+ + " device " + previousDevice + " -> " + newDevice);
}
final int profile = info.getProfile();
if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index 3137fa5784d2..3225274a8a9b 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -116,10 +116,11 @@ public class AudioServiceEvents {
@Override
public String eventToString() {
return new StringBuilder("setWiredDeviceConnectionState(")
- .append(" type:").append(Integer.toHexString(mState.mType))
+ .append(" type:").append(
+ Integer.toHexString(mState.mAttributes.getInternalType()))
.append(" state:").append(AudioSystem.deviceStateToString(mState.mState))
- .append(" addr:").append(mState.mAddress)
- .append(" name:").append(mState.mName)
+ .append(" addr:").append(mState.mAttributes.getAddress())
+ .append(" name:").append(mState.mAttributes.getName())
.append(") from ").append(mState.mCaller).toString();
}
}
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index a2ba76b6fd6a..f572261c09e5 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -258,19 +258,16 @@ public class AudioSystemAdapter implements AudioSystem.RoutingUpdateCallback {
}
/**
- * Same as {@link AudioSystem#setDeviceConnectionState(int, int, String, String, int)}
- * @param device
+ * Same as {@link AudioSystem#setDeviceConnectionState(AudioDeviceAttributes, int, int)}
+ * @param attributes
* @param state
- * @param deviceAddress
- * @param deviceName
* @param codecFormat
* @return
*/
- public int setDeviceConnectionState(int device, int state, String deviceAddress,
- String deviceName, int codecFormat) {
+ public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
+ int codecFormat) {
invalidateRoutingCache();
- return AudioSystem.setDeviceConnectionState(device, state, deviceAddress, deviceName,
- codecFormat);
+ return AudioSystem.setDeviceConnectionState(attributes, state, codecFormat);
}
/**
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 47f31d505867..3491cd59ebb7 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -31,7 +31,7 @@ import android.content.Intent;
import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
-import android.media.BtProfileConnectionInfo;
+import android.media.BluetoothProfileConnectionInfo;
import android.os.Binder;
import android.os.UserHandle;
import android.provider.Settings;
@@ -40,6 +40,7 @@ import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -489,11 +490,13 @@ public class BtHelper {
if (proxy.getConnectionState(btDevice) == BluetoothProfile.STATE_CONNECTED) {
mDeviceBroker.queueOnBluetoothActiveDeviceChanged(
new AudioDeviceBroker.BtDeviceChangedData(btDevice, null,
- new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener"));
+ new BluetoothProfileConnectionInfo(profile),
+ "mBluetoothProfileServiceListener"));
} else {
mDeviceBroker.queueOnBluetoothActiveDeviceChanged(
new AudioDeviceBroker.BtDeviceChangedData(null, btDevice,
- new BtProfileConnectionInfo(profile), "mBluetoothProfileServiceListener"));
+ new BluetoothProfileConnectionInfo(profile),
+ "mBluetoothProfileServiceListener"));
}
}
@@ -503,7 +506,12 @@ public class BtHelper {
// Discard timeout message
mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
mBluetoothHeadset = headset;
- setBtScoActiveDevice(headset != null ? headset.getActiveDevice() : null);
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ List<BluetoothDevice> activeDevices = Collections.emptyList();
+ if (adapter != null) {
+ activeDevices = adapter.getActiveDevices(BluetoothProfile.HEADSET);
+ }
+ setBtScoActiveDevice((activeDevices.size() > 0) ? activeDevices.get(0) : null);
// Refresh SCO audio state
checkScoAudioState();
if (mScoAudioState != SCO_STATE_ACTIVATE_REQ
@@ -587,8 +595,9 @@ public class BtHelper {
String btDeviceName = getName(btDevice);
boolean result = false;
if (isActive) {
- result |= mDeviceBroker.handleDeviceConnection(isActive, audioDevice.getInternalType(),
- audioDevice.getAddress(), btDeviceName);
+ result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
+ audioDevice.getInternalType(), audioDevice.getAddress(), btDeviceName),
+ isActive);
} else {
int[] outDeviceTypes = {
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
@@ -596,13 +605,15 @@ public class BtHelper {
AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
};
for (int outDeviceType : outDeviceTypes) {
- result |= mDeviceBroker.handleDeviceConnection(
- isActive, outDeviceType, audioDevice.getAddress(), btDeviceName);
+ result |= mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
+ outDeviceType, audioDevice.getAddress(), btDeviceName),
+ isActive);
}
}
// handleDeviceConnection() && result to make sure the method get executed
- result = mDeviceBroker.handleDeviceConnection(
- isActive, inDevice, audioDevice.getAddress(), btDeviceName) && result;
+ result = mDeviceBroker.handleDeviceConnection(new AudioDeviceAttributes(
+ inDevice, audioDevice.getAddress(), btDeviceName),
+ isActive) && result;
return result;
}
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index a1d722b6df9d..c46ae851b752 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -69,8 +69,10 @@ public abstract class BrightnessMappingStrategy {
*/
@Nullable
public static BrightnessMappingStrategy create(Resources resources,
- DisplayDeviceConfig displayDeviceConfig) {
- return create(resources, displayDeviceConfig, /* isForIdleMode= */ false, null);
+ DisplayDeviceConfig displayDeviceConfig,
+ DisplayWhiteBalanceController displayWhiteBalanceController) {
+ return create(resources, displayDeviceConfig, /* isForIdleMode= */ false,
+ displayWhiteBalanceController);
}
/**
@@ -845,7 +847,7 @@ public abstract class BrightnessMappingStrategy {
float nits = mBrightnessSpline.interpolate(lux);
// Adjust nits to compensate for display white balance colour strength.
- if (mDisplayWhiteBalanceController != null && isForIdleMode()) {
+ if (mDisplayWhiteBalanceController != null) {
nits = mDisplayWhiteBalanceController.calculateAdjustedBrightnessNits(nits);
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index a4a6eb4312cc..6866137e294e 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -30,6 +30,8 @@ import android.util.Slog;
import android.util.Spline;
import android.view.DisplayAddress;
+import com.android.internal.annotations.VisibleForTesting;
+
import com.android.internal.R;
import com.android.internal.display.BrightnessSynchronizer;
import com.android.server.display.config.BrightnessThresholds;
@@ -40,9 +42,12 @@ import com.android.server.display.config.DisplayConfiguration;
import com.android.server.display.config.DisplayQuirks;
import com.android.server.display.config.HbmTiming;
import com.android.server.display.config.HighBrightnessMode;
+import com.android.server.display.config.Interpolation;
import com.android.server.display.config.NitsMap;
import com.android.server.display.config.Point;
import com.android.server.display.config.RefreshRateRange;
+import com.android.server.display.config.SdrHdrRatioMap;
+import com.android.server.display.config.SdrHdrRatioPoint;
import com.android.server.display.config.SensorDetails;
import com.android.server.display.config.ThermalStatus;
import com.android.server.display.config.ThermalThrottling;
@@ -66,10 +71,126 @@ import java.util.List;
import javax.xml.datatype.DatatypeConfigurationException;
/**
- * Reads and stores display-specific configurations.
+ * Reads and stores display-specific configurations.
+ * File format:
+ * <pre>
+ * {@code
+ * <displayConfiguration>
+ * <densityMap>
+ * <density>
+ * <height>480</height>
+ * <width>720</width>
+ * <density>120</density>
+ * </density>
+ * <density>
+ * <height>720</height>
+ * <width>1280</width>
+ * <density>213</density>
+ * </density>
+ * <density>
+ * <height>1080</height>
+ * <width>1920</width>
+ * <density>320</density>
+ * </density>
+ * <density>
+ * <height>2160</height>
+ * <width>3840</width>
+ * <density>640</density>
+ * </density>
+ * </densityMap>
+ *
+ * <screenBrightnessMap>
+ * <point>
+ * <value>0.0</value>
+ * <nits>2.0</nits>
+ * </point>
+ * <point>
+ * <value>0.62</value>
+ * <nits>500.0</nits>
+ * </point>
+ * <point>
+ * <value>1.0</value>
+ * <nits>800.0</nits>
+ * </point>
+ * </screenBrightnessMap>
+ *
+ * <screenBrightnessDefault>0.65</screenBrightnessDefault>
+ *
+ * <thermalThrottling>
+ * <brightnessThrottlingMap>
+ * <brightnessThrottlingPoint>
+ * <thermalStatus>severe</thermalStatus>
+ * <brightness>0.1</brightness>
+ * </brightnessThrottlingPoint>
+ * <brightnessThrottlingPoint>
+ * <thermalStatus>critical</thermalStatus>
+ * <brightness>0.01</brightness>
+ * </brightnessThrottlingPoint>
+ * </brightnessThrottlingMap>
+ * </thermalThrottling>
+ *
+ * <highBrightnessMode enabled="true">
+ * <transitionPoint>0.62</transitionPoint>
+ * <minimumLux>10000</minimumLux>
+ * <timing>
+ * <timeWindowSecs>1800</timeWindowSecs> // Window in which we restrict HBM.
+ * <timeMaxSecs>300</timeMaxSecs> // Maximum time of HBM allowed in that window.
+ * <timeMinSecs>60</timeMinSecs> // Minimum time remaining required to switch
+ * </timing> // HBM on for.
+ * <refreshRate>
+ * <minimum>120</minimum>
+ * <maximum>120</maximum>
+ * </refreshRate>
+ * <thermalStatusLimit>light</thermalStatusLimit>
+ * <allowInLowPowerMode>false</allowInLowPowerMode>
+ * </highBrightnessMode>
+ *
+ * <quirks>
+ * <quirk>canSetBrightnessViaHwc</quirk>
+ * </quirks>
+ *
+ * <screenBrightnessRampFastDecrease>0.01</screenBrightnessRampFastDecrease>
+ * <screenBrightnessRampFastIncrease>0.02</screenBrightnessRampFastIncrease>
+ * <screenBrightnessRampSlowDecrease>0.03</screenBrightnessRampSlowDecrease>
+ * <screenBrightnessRampSlowIncrease>0.04</screenBrightnessRampSlowIncrease>
+ *
+ * <lightSensor>
+ * <type>android.sensor.light</type>
+ * <name>1234 Ambient Light Sensor</name>
+ * </lightSensor>
+ * <proxSensor>
+ * <type>android.sensor.proximity</type>
+ * <name>1234 Proximity Sensor</name>
+ * </proxSensor>
+ *
+ * <ambientLightHorizonLong>10001</ambientLightHorizonLong>
+ * <ambientLightHorizonShort>2001</ambientLightHorizonShort>
+ *
+ * <displayBrightnessChangeThresholds>
+ * <brighteningThresholds>
+ * <minimum>0.001</minimum> // Minimum change needed in screen brightness to brighten.
+ * </brighteningThresholds>
+ * <darkeningThresholds>
+ * <minimum>0.002</minimum> // Minimum change needed in screen brightness to darken.
+ * </darkeningThresholds>
+ * </displayBrightnessChangeThresholds>
+ *
+ * <ambientBrightnessChangeThresholds>
+ * <brighteningThresholds>
+ * <minimum>0.003</minimum> // Minimum change needed in ambient brightness to brighten.
+ * </brighteningThresholds>
+ * <darkeningThresholds>
+ * <minimum>0.004</minimum> // Minimum change needed in ambient brightness to darken.
+ * </darkeningThresholds>
+ * </ambientBrightnessChangeThresholds>
+ *
+ * </displayConfiguration>
+ * }
+ * </pre>
*/
public class DisplayDeviceConfig {
private static final String TAG = "DisplayDeviceConfig";
+ private static final boolean DEBUG = false;
public static final float HIGH_BRIGHTNESS_MODE_UNSUPPORTED = Float.NaN;
@@ -86,6 +207,9 @@ public class DisplayDeviceConfig {
private static final String NO_SUFFIX_FORMAT = "%d";
private static final long STABLE_FLAG = 1L << 62;
+ private static final int INTERPOLATION_DEFAULT = 0;
+ private static final int INTERPOLATION_LINEAR = 1;
+
// Float.NaN (used as invalid for brightness) cannot be stored in config.xml
// so -2 is used instead
private static final float INVALID_BRIGHTNESS_IN_CONFIG = -2f;
@@ -99,6 +223,9 @@ public class DisplayDeviceConfig {
// Length of the ambient light horizon used to calculate short-term estimate of ambient light.
private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
+ @VisibleForTesting
+ static final float HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT = 0.5f;
+
private final Context mContext;
// The details of the ambient light sensor associated with this display.
@@ -114,6 +241,7 @@ public class DisplayDeviceConfig {
// config.xml. These are the raw values and just used for the dumpsys
private float[] mRawNits;
private float[] mRawBacklight;
+ private int mInterpolationType;
// These arrays are calculated from the raw arrays, but clamped to contain values equal to and
// between mBacklightMinimum and mBacklightMaximum. These three arrays should all be the same
@@ -142,6 +270,7 @@ public class DisplayDeviceConfig {
private Spline mBrightnessToBacklightSpline;
private Spline mBacklightToBrightnessSpline;
private Spline mBacklightToNitsSpline;
+ private Spline mNitsToBacklightSpline;
private List<String> mQuirks;
private boolean mIsHighBrightnessModeEnabled = false;
private HighBrightnessModeData mHbmData;
@@ -149,6 +278,7 @@ public class DisplayDeviceConfig {
private String mLoadedFrom = null;
private BrightnessThrottlingData mBrightnessThrottlingData;
+ private Spline mSdrToHdrRatioSpline;
private DisplayDeviceConfig(Context context) {
mContext = context;
@@ -333,6 +463,45 @@ public class DisplayDeviceConfig {
}
/**
+ * Calculate the HDR brightness for the specified SDR brightenss.
+ *
+ * @return the HDR brightness or BRIGHTNESS_INVALID when no mapping exists.
+ */
+ public float getHdrBrightnessFromSdr(float brightness) {
+ if (mSdrToHdrRatioSpline == null) {
+ return PowerManager.BRIGHTNESS_INVALID;
+ }
+
+ float backlight = getBacklightFromBrightness(brightness);
+ float nits = getNitsFromBacklight(backlight);
+ if (nits == NITS_INVALID) {
+ return PowerManager.BRIGHTNESS_INVALID;
+ }
+
+ float ratio = mSdrToHdrRatioSpline.interpolate(nits);
+ float hdrNits = nits * ratio;
+ if (mNitsToBacklightSpline == null) {
+ return PowerManager.BRIGHTNESS_INVALID;
+ }
+
+ float hdrBacklight = mNitsToBacklightSpline.interpolate(hdrNits);
+ hdrBacklight = Math.max(mBacklightMinimum, Math.min(mBacklightMaximum, hdrBacklight));
+ float hdrBrightness = mBacklightToBrightnessSpline.interpolate(hdrBacklight);
+
+ if (DEBUG) {
+ Slog.d(TAG, "getHdrBrightnessFromSdr: sdr brightness " + brightness
+ + " backlight " + backlight
+ + " nits " + nits
+ + " ratio " + ratio
+ + " hdrNits " + hdrNits
+ + " hdrBacklight " + hdrBacklight
+ + " hdrBrightness " + hdrBrightness
+ );
+ }
+ return hdrBrightness;
+ }
+
+ /**
* Return an array of equal length to backlight and nits, that covers the entire system
* brightness range of 0.0-1.0.
*
@@ -444,15 +613,18 @@ public class DisplayDeviceConfig {
+ ", mNits=" + Arrays.toString(mNits)
+ ", mRawBacklight=" + Arrays.toString(mRawBacklight)
+ ", mRawNits=" + Arrays.toString(mRawNits)
+ + ", mInterpolationType=" + mInterpolationType
+ ", mBrightness=" + Arrays.toString(mBrightness)
+ ", mBrightnessToBacklightSpline=" + mBrightnessToBacklightSpline
+ ", mBacklightToBrightnessSpline=" + mBacklightToBrightnessSpline
+ + ", mNitsToBacklightSpline=" + mNitsToBacklightSpline
+ ", mBacklightMinimum=" + mBacklightMinimum
+ ", mBacklightMaximum=" + mBacklightMaximum
+ ", mBrightnessDefault=" + mBrightnessDefault
+ ", mQuirks=" + mQuirks
+ ", isHbmEnabled=" + mIsHighBrightnessModeEnabled
+ ", mHbmData=" + mHbmData
+ + ", mSdrToHdrRatioSpline=" + mSdrToHdrRatioSpline
+ ", mBrightnessThrottlingData=" + mBrightnessThrottlingData
+ ", mBrightnessRampFastDecrease=" + mBrightnessRampFastDecrease
+ ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
@@ -653,6 +825,7 @@ public class DisplayDeviceConfig {
float[] nits = new float[size];
float[] backlight = new float[size];
+ mInterpolationType = convertInterpolationType(map.getInterpolation());
int i = 0;
for (Point point : points) {
nits[i] = point.getNits().floatValue();
@@ -678,6 +851,40 @@ public class DisplayDeviceConfig {
constrainNitsAndBacklightArrays();
}
+ private Spline loadSdrHdrRatioMap(HighBrightnessMode hbmConfig) {
+ final SdrHdrRatioMap sdrHdrRatioMap = hbmConfig.getSdrHdrRatioMap_all();
+
+ if (sdrHdrRatioMap == null) {
+ return null;
+ }
+
+ final List<SdrHdrRatioPoint> points = sdrHdrRatioMap.getPoint();
+ final int size = points.size();
+ if (size <= 0) {
+ return null;
+ }
+
+ float[] nits = new float[size];
+ float[] ratios = new float[size];
+
+ int i = 0;
+ for (SdrHdrRatioPoint point : points) {
+ nits[i] = point.getSdrNits().floatValue();
+ if (i > 0) {
+ if (nits[i] < nits[i - 1]) {
+ Slog.e(TAG, "sdrHdrRatioMap must be non-decreasing, ignoring rest "
+ + " of configuration. nits: " + nits[i] + " < "
+ + nits[i - 1]);
+ return null;
+ }
+ }
+ ratios[i] = point.getHdrRatio().floatValue();
+ ++i;
+ }
+
+ return Spline.createSpline(nits, ratios);
+ }
+
private void loadBrightnessThrottlingMap(DisplayConfiguration config) {
final ThermalThrottling throttlingConfig = config.getThermalThrottling();
if (throttlingConfig == null) {
@@ -823,9 +1030,18 @@ public class DisplayDeviceConfig {
mBacklight[mBacklight.length - 1],
PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, mBacklight[i]);
}
- mBrightnessToBacklightSpline = Spline.createSpline(mBrightness, mBacklight);
- mBacklightToBrightnessSpline = Spline.createSpline(mBacklight, mBrightness);
- mBacklightToNitsSpline = Spline.createSpline(mBacklight, mNits);
+ mBrightnessToBacklightSpline = mInterpolationType == INTERPOLATION_LINEAR
+ ? Spline.createLinearSpline(mBrightness, mBacklight)
+ : Spline.createSpline(mBrightness, mBacklight);
+ mBacklightToBrightnessSpline = mInterpolationType == INTERPOLATION_LINEAR
+ ? Spline.createLinearSpline(mBacklight, mBrightness)
+ : Spline.createSpline(mBacklight, mBrightness);
+ mBacklightToNitsSpline = mInterpolationType == INTERPOLATION_LINEAR
+ ? Spline.createLinearSpline(mBacklight, mNits)
+ : Spline.createSpline(mBacklight, mNits);
+ mNitsToBacklightSpline = mInterpolationType == INTERPOLATION_LINEAR
+ ? Spline.createLinearSpline(mNits, mBacklight)
+ : Spline.createSpline(mNits, mBacklight);
}
private void loadQuirks(DisplayConfiguration config) {
@@ -862,6 +1078,20 @@ public class DisplayDeviceConfig {
mRefreshRateLimitations.add(new RefreshRateLimitation(
DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE, min, max));
}
+ BigDecimal minHdrPctOfScreen = hbm.getMinimumHdrPercentOfScreen_all();
+ if (minHdrPctOfScreen != null) {
+ mHbmData.minimumHdrPercentOfScreen = minHdrPctOfScreen.floatValue();
+ if (mHbmData.minimumHdrPercentOfScreen > 1
+ || mHbmData.minimumHdrPercentOfScreen < 0) {
+ Slog.w(TAG, "Invalid minimum HDR percent of screen: "
+ + String.valueOf(mHbmData.minimumHdrPercentOfScreen));
+ mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
+ }
+ } else {
+ mHbmData.minimumHdrPercentOfScreen = HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
+ }
+
+ mSdrToHdrRatioSpline = loadSdrHdrRatioMap(hbm);
}
}
@@ -1024,6 +1254,21 @@ public class DisplayDeviceConfig {
}
}
+ private int convertInterpolationType(Interpolation value) {
+ if (value == null) {
+ return INTERPOLATION_DEFAULT;
+ }
+ switch (value) {
+ case _default:
+ return INTERPOLATION_DEFAULT;
+ case linear:
+ return INTERPOLATION_LINEAR;
+ default:
+ Slog.wtf(TAG, "Unexpected Interpolation Type: " + value);
+ return INTERPOLATION_DEFAULT;
+ }
+ }
+
private void loadAmbientHorizonFromDdc(DisplayConfiguration config) {
final BigInteger configLongHorizon = config.getAmbientLightHorizonLong();
if (configLongHorizon != null) {
@@ -1088,11 +1333,15 @@ public class DisplayDeviceConfig {
/** Minimum time that HBM can be on before being enabled. */
public long timeMinMillis;
+ /** Minimum HDR video size to enter high brightness mode */
+ public float minimumHdrPercentOfScreen;
+
HighBrightnessModeData() {}
HighBrightnessModeData(float minimumLux, float transitionPoint, long timeWindowMillis,
long timeMaxMillis, long timeMinMillis,
- @PowerManager.ThermalStatus int thermalStatusLimit, boolean allowInLowPowerMode) {
+ @PowerManager.ThermalStatus int thermalStatusLimit, boolean allowInLowPowerMode,
+ float minimumHdrPercentOfScreen) {
this.minimumLux = minimumLux;
this.transitionPoint = transitionPoint;
this.timeWindowMillis = timeWindowMillis;
@@ -1100,6 +1349,7 @@ public class DisplayDeviceConfig {
this.timeMinMillis = timeMinMillis;
this.thermalStatusLimit = thermalStatusLimit;
this.allowInLowPowerMode = allowInLowPowerMode;
+ this.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
}
/**
@@ -1114,6 +1364,7 @@ public class DisplayDeviceConfig {
other.transitionPoint = transitionPoint;
other.thermalStatusLimit = thermalStatusLimit;
other.allowInLowPowerMode = allowInLowPowerMode;
+ other.minimumHdrPercentOfScreen = minimumHdrPercentOfScreen;
}
@Override
@@ -1126,6 +1377,7 @@ public class DisplayDeviceConfig {
+ ", timeMin: " + timeMinMillis + "ms"
+ ", thermalStatusLimit: " + thermalStatusLimit
+ ", allowInLowPowerMode: " + allowInLowPowerMode
+ + ", minimumHdrPercentOfScreen: " + minimumHdrPercentOfScreen
+ "} ";
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 6ae1a5a96a24..d71e07ab573f 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -546,28 +546,6 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// Seed the cached brightness
saveBrightnessInfo(getScreenBrightnessSetting());
- setUpAutoBrightness(resources, handler);
-
- mColorFadeEnabled = !ActivityManager.isLowRamDeviceStatic();
- mColorFadeFadesConfig = resources.getBoolean(
- com.android.internal.R.bool.config_animateScreenLights);
-
- mDisplayBlanksAfterDozeConfig = resources.getBoolean(
- com.android.internal.R.bool.config_displayBlanksAfterDoze);
-
- mBrightnessBucketsInDozeConfig = resources.getBoolean(
- com.android.internal.R.bool.config_displayBrightnessBucketsInDoze);
-
- loadProximitySensor();
-
- mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
- mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
- mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
- mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
- mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-
DisplayWhiteBalanceSettings displayWhiteBalanceSettings = null;
DisplayWhiteBalanceController displayWhiteBalanceController = null;
if (mDisplayId == Display.DEFAULT_DISPLAY) {
@@ -610,6 +588,29 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
} else {
mCdsi = null;
}
+
+ setUpAutoBrightness(resources, handler);
+
+ mColorFadeEnabled = !ActivityManager.isLowRamDeviceStatic();
+ mColorFadeFadesConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_animateScreenLights);
+
+ mDisplayBlanksAfterDozeConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_displayBlanksAfterDoze);
+
+ mBrightnessBucketsInDozeConfig = resources.getBoolean(
+ com.android.internal.R.bool.config_displayBrightnessBucketsInDoze);
+
+ loadProximitySensor();
+
+ mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
+ mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
+ mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
+ mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+
}
private void applyReduceBrightColorsSplineAdjustment(
@@ -831,7 +832,13 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
setUpAutoBrightness(mContext.getResources(), mHandler);
reloadReduceBrightColours();
mHbmController.resetHbmData(info.width, info.height, token, info.uniqueId,
- mDisplayDeviceConfig.getHighBrightnessModeData());
+ mDisplayDeviceConfig.getHighBrightnessModeData(),
+ new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
+ @Override
+ public float getHdrBrightnessFromSdr(float sdrBrightness) {
+ return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
+ }
+ });
mBrightnessThrottler.resetThrottlingData(
mDisplayDeviceConfig.getBrightnessThrottlingData());
}
@@ -901,7 +908,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
final boolean isIdleScreenBrightnessEnabled = resources.getBoolean(
R.bool.config_enableIdleScreenBrightnessMode);
mInteractiveModeBrightnessMapper = BrightnessMappingStrategy.create(resources,
- mDisplayDeviceConfig);
+ mDisplayDeviceConfig, mDisplayWhiteBalanceController);
if (isIdleScreenBrightnessEnabled) {
mIdleModeBrightnessMapper = BrightnessMappingStrategy.createForIdleMode(resources,
mDisplayDeviceConfig, mDisplayWhiteBalanceController);
@@ -1713,6 +1720,12 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
return new HighBrightnessModeController(mHandler, info.width, info.height, displayToken,
displayUniqueId, PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
+ new HighBrightnessModeController.HdrBrightnessDeviceConfig() {
+ @Override
+ public float getHdrBrightnessFromSdr(float sdrBrightness) {
+ return mDisplayDeviceConfig.getHdrBrightnessFromSdr(sdrBrightness);
+ }
+ },
() -> {
sendUpdatePowerStateLocked();
postBrightnessChangeRunnable();
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index 23c17f5af10d..0b9d4debd16f 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -58,11 +58,13 @@ class HighBrightnessModeController {
private static final boolean DEBUG = false;
- private static final float HDR_PERCENT_OF_SCREEN_REQUIRED = 0.50f;
-
@VisibleForTesting
static final float HBM_TRANSITION_POINT_INVALID = Float.POSITIVE_INFINITY;
+ public interface HdrBrightnessDeviceConfig {
+ float getHdrBrightnessFromSdr(float sdrBrightness);
+ }
+
private final float mBrightnessMin;
private final float mBrightnessMax;
private final Handler mHandler;
@@ -76,6 +78,7 @@ class HighBrightnessModeController {
private HdrListener mHdrListener;
private HighBrightnessModeData mHbmData;
+ private HdrBrightnessDeviceConfig mHdrBrightnessCfg;
private IBinder mRegisteredDisplayToken;
private boolean mIsInAllowedAmbientRange = false;
@@ -115,16 +118,17 @@ class HighBrightnessModeController {
HighBrightnessModeController(Handler handler, int width, int height, IBinder displayToken,
String displayUniqueId, float brightnessMin, float brightnessMax,
- HighBrightnessModeData hbmData, Runnable hbmChangeCallback, Context context) {
+ HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg,
+ Runnable hbmChangeCallback, Context context) {
this(new Injector(), handler, width, height, displayToken, displayUniqueId, brightnessMin,
- brightnessMax, hbmData, hbmChangeCallback, context);
+ brightnessMax, hbmData, hdrBrightnessCfg, hbmChangeCallback, context);
}
@VisibleForTesting
HighBrightnessModeController(Injector injector, Handler handler, int width, int height,
IBinder displayToken, String displayUniqueId, float brightnessMin, float brightnessMax,
- HighBrightnessModeData hbmData, Runnable hbmChangeCallback,
- Context context) {
+ HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg,
+ Runnable hbmChangeCallback, Context context) {
mInjector = injector;
mContext = context;
mClock = injector.getClock();
@@ -138,7 +142,7 @@ class HighBrightnessModeController {
mRecalcRunnable = this::recalculateTimeAllowance;
mHdrListener = new HdrListener();
- resetHbmData(width, height, displayToken, displayUniqueId, hbmData);
+ resetHbmData(width, height, displayToken, displayUniqueId, hbmData, hdrBrightnessCfg);
}
void setAutoBrightnessEnabled(int state) {
@@ -178,6 +182,13 @@ class HighBrightnessModeController {
}
float getHdrBrightnessValue() {
+ if (mHdrBrightnessCfg != null) {
+ float hdrBrightness = mHdrBrightnessCfg.getHdrBrightnessFromSdr(mBrightness);
+ if (hdrBrightness != PowerManager.BRIGHTNESS_INVALID) {
+ return hdrBrightness;
+ }
+ }
+
// For HDR brightness, we take the current brightness and scale it to the max. The reason
// we do this is because we want brightness to go to HBM max when it would normally go
// to normal max, meaning it should not wait to go to 10000 lux (or whatever the transition
@@ -250,10 +261,11 @@ class HighBrightnessModeController {
}
void resetHbmData(int width, int height, IBinder displayToken, String displayUniqueId,
- HighBrightnessModeData hbmData) {
+ HighBrightnessModeData hbmData, HdrBrightnessDeviceConfig hdrBrightnessCfg) {
mWidth = width;
mHeight = height;
mHbmData = hbmData;
+ mHdrBrightnessCfg = hdrBrightnessCfg;
mDisplayStatsId = displayUniqueId.hashCode();
unregisterHdrListener();
@@ -602,8 +614,8 @@ class HighBrightnessModeController {
int maxW, int maxH, int flags) {
mHandler.post(() -> {
mIsHdrLayerPresent = numberOfHdrLayers > 0
- && (float) (maxW * maxH)
- >= ((float) (mWidth * mHeight) * HDR_PERCENT_OF_SCREEN_REQUIRED);
+ && (float) (maxW * maxH) >= ((float) (mWidth * mHeight)
+ * mHbmData.minimumHdrPercentOfScreen);
// Calling the brightness update so that we can recalculate
// brightness with HDR in mind.
onBrightnessChanged(mBrightness, mUnthrottledBrightness, mThrottlingReason);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index afcd3dde0633..1ce36b181eb0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -41,7 +41,10 @@ import android.hardware.hdmi.HdmiRecordSources;
import android.hardware.hdmi.HdmiTimerRecordSources;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.tv.cec.V1_0.SendMessageResult;
-import android.media.AudioSystem;
+import android.media.AudioDescriptor;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioDeviceInfo;
+import android.media.AudioProfile;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager.TvInputCallback;
import android.util.Slog;
@@ -58,6 +61,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Represent a logical device of type TV residing in Android system.
@@ -816,12 +820,23 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
boolean oldStatus = mArcEstablished;
- // 1. Enable/disable ARC circuit.
- enableAudioReturnChannel(enabled);
- // 2. Notify arc status to audio service.
- notifyArcStatusToAudioService(enabled);
- // 3. Update arc status;
- mArcEstablished = enabled;
+ if (enabled) {
+ RequestSadAction action = new RequestSadAction(
+ this, Constants.ADDR_AUDIO_SYSTEM,
+ new RequestSadAction.RequestSadCallback() {
+ @Override
+ public void onRequestSadDone(List<byte[]> supportedSads) {
+ enableAudioReturnChannel(enabled);
+ notifyArcStatusToAudioService(enabled, supportedSads);
+ mArcEstablished = enabled;
+ }
+ });
+ addAndStartAction(action);
+ } else {
+ enableAudioReturnChannel(enabled);
+ notifyArcStatusToAudioService(enabled, new ArrayList<>());
+ mArcEstablished = enabled;
+ }
return oldStatus;
}
@@ -843,11 +858,15 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
return mService.isConnected(portId);
}
- private void notifyArcStatusToAudioService(boolean enabled) {
+ private void notifyArcStatusToAudioService(boolean enabled, List<byte[]> supportedSads) {
// Note that we don't set any name to ARC.
- mService.getAudioManager().setWiredDeviceConnectionState(
- AudioSystem.DEVICE_OUT_HDMI_ARC,
- enabled ? 1 : 0, "", "");
+ AudioDeviceAttributes attributes = new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_HDMI_ARC, "", "",
+ new ArrayList<AudioProfile>(), supportedSads.stream()
+ .map(sad -> new AudioDescriptor(AudioDescriptor.STANDARD_EDID,
+ AudioProfile.AUDIO_ENCAPSULATION_TYPE_NONE, sad))
+ .collect(Collectors.toList()));
+ mService.getAudioManager().setWiredDeviceConnectionState(attributes, enabled ? 1 : 0);
}
/**
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index bfaa7b37fa33..354d1838709d 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -150,8 +150,6 @@ public class InputManagerService extends IInputManager.Stub
static final String TAG = "InputManager";
static final boolean DEBUG = false;
- private static final boolean USE_SPY_WINDOW_GESTURE_MONITORS = true;
-
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml";
private static final String PORT_ASSOCIATIONS_PATH = "etc/input-port-associations.xml";
@@ -303,7 +301,7 @@ public class InputManagerService extends IInputManager.Stub
int locationKeyCode);
private static native InputChannel nativeCreateInputChannel(long ptr, String name);
private static native InputChannel nativeCreateInputMonitor(long ptr, int displayId,
- boolean isGestureMonitor, String name, int pid);
+ String name, int pid);
private static native void nativeRemoveInputChannel(long ptr, IBinder connectionToken);
private static native void nativePilferPointers(long ptr, IBinder token);
private static native void nativeSetInputFilterEnabled(long ptr, boolean enable);
@@ -720,8 +718,7 @@ public class InputManagerService extends IInputManager.Stub
throw new IllegalArgumentException("displayId must >= 0.");
}
- return nativeCreateInputMonitor(mPtr, displayId, false /* isGestureMonitor */,
- inputChannelName, Binder.getCallingPid());
+ return nativeCreateInputMonitor(mPtr, displayId, inputChannelName, Binder.getCallingPid());
}
@NonNull
@@ -790,10 +787,7 @@ public class InputManagerService extends IInputManager.Stub
final long ident = Binder.clearCallingIdentity();
try {
final InputChannel inputChannel =
- USE_SPY_WINDOW_GESTURE_MONITORS
- ? createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid)
- : nativeCreateInputMonitor(mPtr, displayId, true /*isGestureMonitor*/,
- requestedName, pid);
+ createSpyWindowGestureMonitor(monitorToken, name, displayId, pid, uid);
return new InputMonitor(inputChannel, new InputMonitorHost(inputChannel.getToken()));
} finally {
Binder.restoreCallingIdentity(ident);
@@ -3375,11 +3369,7 @@ public class InputManagerService extends IInputManager.Stub
@Override
public void dispose() {
- if (USE_SPY_WINDOW_GESTURE_MONITORS) {
- removeSpyWindowGestureMonitor(mInputChannelToken);
- return;
- }
- nativeRemoveInputChannel(mPtr, mInputChannelToken);
+ removeSpyWindowGestureMonitor(mInputChannelToken);
}
}
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index caec391be418..9846a2ba48a4 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -56,7 +56,8 @@ final class HandwritingEventReceiverSurface {
mWindowHandle.name = name;
mWindowHandle.token = mClientChannel.getToken();
mWindowHandle.layoutParamsType = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
- mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
mWindowHandle.dispatchingTimeoutMillis = DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
mWindowHandle.visible = true;
mWindowHandle.focusable = false;
diff --git a/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java b/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java
new file mode 100644
index 000000000000..6b442a6a395e
--- /dev/null
+++ b/services/core/java/com/android/server/logcat/LogAccessConfirmationActivity.java
@@ -0,0 +1,130 @@
+/*
+ * 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 com.android.server.logcat;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.os.Bundle;
+import android.os.ServiceManager;
+import android.os.logcat.ILogcatManagerService;
+import android.util.Slog;
+import android.view.View;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+
+/**
+ * This dialog is shown to the user before an activity in a harmful app is launched.
+ *
+ * See {@code PackageManager.setLogcatAppInfo} for more info.
+ */
+public class LogAccessConfirmationActivity extends AlertActivity implements
+ DialogInterface.OnClickListener {
+ private static final String TAG = LogAccessConfirmationActivity.class.getSimpleName();
+
+ private String mPackageName;
+ private IntentSender mTarget;
+ private final ILogcatManagerService mLogcatManagerService =
+ ILogcatManagerService.Stub.asInterface(ServiceManager.getService("logcat"));
+
+ private int mUid;
+ private int mGid;
+ private int mPid;
+ private int mFd;
+
+ private static final String EXTRA_UID = "uid";
+ private static final String EXTRA_GID = "gid";
+ private static final String EXTRA_PID = "pid";
+ private static final String EXTRA_FD = "fd";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final Intent intent = getIntent();
+ mPackageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+ mUid = intent.getIntExtra("uid", 0);
+ mGid = intent.getIntExtra("gid", 0);
+ mPid = intent.getIntExtra("pid", 0);
+ mFd = intent.getIntExtra("fd", 0);
+
+ final AlertController.AlertParams p = mAlertParams;
+ p.mTitle = getString(R.string.log_access_confirmation_title);
+ p.mView = createView();
+
+ p.mPositiveButtonText = getString(R.string.log_access_confirmation_allow);
+ p.mPositiveButtonListener = this;
+ p.mNegativeButtonText = getString(R.string.log_access_confirmation_deny);
+ p.mNegativeButtonListener = this;
+
+ mAlert.installContent(mAlertParams);
+ }
+
+ private View createView() {
+ final View view = getLayoutInflater().inflate(R.layout.harmful_app_warning_dialog,
+ null /*root*/);
+ ((TextView) view.findViewById(R.id.app_name_text))
+ .setText(mPackageName);
+ ((TextView) view.findViewById(R.id.message))
+ .setText(getIntent().getExtras().getString("body"));
+ return view;
+ }
+
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE:
+ try {
+ mLogcatManagerService.approve(mUid, mGid, mPid, mFd);
+ } catch (Throwable t) {
+ Slog.e(TAG, "Could not start the LogcatManagerService.", t);
+ }
+ finish();
+ break;
+ case DialogInterface.BUTTON_NEGATIVE:
+ try {
+ mLogcatManagerService.decline(mUid, mGid, mPid, mFd);
+ } catch (Throwable t) {
+ Slog.e(TAG, "Could not start the LogcatManagerService.", t);
+ }
+ finish();
+ break;
+ }
+ }
+
+ /**
+ * Create the Intent for a LogAccessConfirmationActivity.
+ */
+ public static Intent createIntent(Context context, String targetPackageName,
+ IntentSender target, int uid, int gid, int pid, int fd) {
+ final Intent intent = new Intent();
+ intent.setClass(context, LogAccessConfirmationActivity.class);
+ intent.putExtra(Intent.EXTRA_PACKAGE_NAME, targetPackageName);
+ intent.putExtra(EXTRA_UID, uid);
+ intent.putExtra(EXTRA_GID, gid);
+ intent.putExtra(EXTRA_PID, pid);
+ intent.putExtra(EXTRA_FD, fd);
+
+ return intent;
+ }
+
+}
diff --git a/services/core/java/com/android/server/logcat/LogcatManagerService.java b/services/core/java/com/android/server/logcat/LogcatManagerService.java
index ff6372aec3bd..140c6d48b57b 100644
--- a/services/core/java/com/android/server/logcat/LogcatManagerService.java
+++ b/services/core/java/com/android/server/logcat/LogcatManagerService.java
@@ -16,20 +16,36 @@
package com.android.server.logcat;
+import android.annotation.NonNull;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ActivityManagerInternal;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.ILogd;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.os.logcat.ILogcatManagerService;
import android.util.Slog;
+import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.LocalServices;
import com.android.server.SystemService;
+import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
- * Service responsible for manage the access to Logcat.
+ * Service responsible for managing the access to Logcat.
*/
public final class LogcatManagerService extends SystemService {
@@ -38,6 +54,43 @@ public final class LogcatManagerService extends SystemService {
private final BinderService mBinderService;
private final ExecutorService mThreadExecutor;
private ILogd mLogdService;
+ private NotificationManager mNotificationManager;
+ private @NonNull ActivityManager mActivityManager;
+ private ActivityManagerInternal mActivityManagerInternal;
+ private static final int MAX_UID_IMPORTANCE_COUNT_LISTENER = 2;
+ private static int sUidImportanceListenerCount = 0;
+ private static final int AID_SHELL_UID = 2000;
+
+ // TODO This allowlist is just a temporary workaround for the tests:
+ // FrameworksServicesTests
+ // PlatformRuleTests
+ // After adapting the test suites, the allowlist will be removed in
+ // the upcoming bug fix patches.
+ private static final String[] ALLOWABLE_TESTING_PACKAGES = {
+ "android.platform.test.rule.tests",
+ "com.android.frameworks.servicestests"
+ };
+
+ // TODO Same as the above ALLOWABLE_TESTING_PACKAGES.
+ private boolean isAllowableTestingPackage(int uid) {
+ PackageManager pm = mContext.getPackageManager();
+
+ String[] packageNames = pm.getPackagesForUid(uid);
+
+ if (ArrayUtils.isEmpty(packageNames)) {
+ return false;
+ }
+
+ for (String name : packageNames) {
+ Slog.e(TAG, "isAllowableTestingPackage: " + name);
+
+ if (Arrays.asList(ALLOWABLE_TESTING_PACKAGES).contains(name)) {
+ return true;
+ }
+ }
+
+ return false;
+ };
private final class BinderService extends ILogcatManagerService.Stub {
@Override
@@ -51,6 +104,197 @@ public final class LogcatManagerService extends SystemService {
// the logd data access is finished.
mThreadExecutor.execute(new LogdMonitor(uid, gid, pid, fd, false));
}
+
+ @Override
+ public void approve(int uid, int gid, int pid, int fd) {
+ try {
+ getLogdService().approve(uid, gid, pid, fd);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void decline(int uid, int gid, int pid, int fd) {
+ try {
+ getLogdService().decline(uid, gid, pid, fd);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private ILogd getLogdService() {
+ synchronized (LogcatManagerService.this) {
+ if (mLogdService == null) {
+ LogcatManagerService.this.addLogdService();
+ }
+ return mLogdService;
+ }
+ }
+
+ private String getBodyString(Context context, String callingPackage, int uid) {
+ PackageManager pm = context.getPackageManager();
+ try {
+ return context.getString(
+ com.android.internal.R.string.log_access_confirmation_body,
+ pm.getApplicationInfoAsUser(callingPackage, PackageManager.MATCH_DIRECT_BOOT_AUTO,
+ UserHandle.getUserId(uid)).loadLabel(pm));
+ } catch (NameNotFoundException e) {
+ // App name is unknown.
+ return null;
+ }
+ }
+
+ private void sendNotification(int notificationId, String clientInfo, int uid, int gid, int pid,
+ int fd) {
+
+ final ActivityManagerInternal activityManagerInternal =
+ LocalServices.getService(ActivityManagerInternal.class);
+
+ PackageManager pm = mContext.getPackageManager();
+ String packageName = activityManagerInternal.getPackageNameByPid(pid);
+ if (packageName != null) {
+ String notificationBody = getBodyString(mContext, packageName, uid);
+
+ final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
+ packageName, null, uid, gid, pid, fd);
+
+ if (notificationBody == null) {
+ // Decline the logd access if the nofitication body is unknown
+ Slog.e(TAG, "Unknown notification body, declining the logd access");
+ declineLogdAccess(uid, gid, pid, fd);
+ return;
+ }
+
+ // TODO Next version will replace notification with dialogue
+ // per UX guidance.
+ generateNotificationWithBodyContent(notificationId, clientInfo, notificationBody,
+ mIntent);
+ return;
+
+ }
+
+ String[] packageNames = pm.getPackagesForUid(uid);
+
+ if (ArrayUtils.isEmpty(packageNames)) {
+ // Decline the logd access if the app name is unknown
+ Slog.e(TAG, "Unknown calling package name, declining the logd access");
+ declineLogdAccess(uid, gid, pid, fd);
+ return;
+ }
+
+ String firstPackageName = packageNames[0];
+
+ if (firstPackageName == null || firstPackageName.length() == 0) {
+ // Decline the logd access if the package name from uid is unknown
+ Slog.e(TAG, "Unknown calling package name, declining the logd access");
+ declineLogdAccess(uid, gid, pid, fd);
+ return;
+ }
+
+ String notificationBody = getBodyString(mContext, firstPackageName, uid);
+
+ final Intent mIntent = LogAccessConfirmationActivity.createIntent(mContext,
+ firstPackageName, null, uid, gid, pid, fd);
+
+ if (notificationBody == null) {
+ Slog.e(TAG, "Unknown notification body, declining the logd access");
+ declineLogdAccess(uid, gid, pid, fd);
+ return;
+ }
+
+ // TODO Next version will replace notification with dialogue
+ // per UX guidance.
+ generateNotificationWithBodyContent(notificationId, clientInfo,
+ notificationBody, mIntent);
+ }
+
+ private void declineLogdAccess(int uid, int gid, int pid, int fd) {
+ try {
+ getLogdService().decline(uid, gid, pid, fd);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Fails to call remote functions ", ex);
+ }
+ }
+
+ private void generateNotificationWithBodyContent(int notificationId, String clientInfo,
+ String notificationBody, Intent intent) {
+ final Notification.Builder notificationBuilder = new Notification.Builder(
+ mContext,
+ SystemNotificationChannels.ACCESSIBILITY_SECURITY_POLICY);
+ intent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ intent.setIdentifier(String.valueOf(notificationId) + clientInfo);
+ intent.putExtra("body", notificationBody);
+
+ notificationBuilder
+ .setSmallIcon(R.drawable.ic_info)
+ .setContentTitle(
+ mContext.getString(R.string.log_access_confirmation_title))
+ .setContentText(notificationBody)
+ .setContentIntent(
+ PendingIntent.getActivity(mContext, 0, intent,
+ PendingIntent.FLAG_IMMUTABLE))
+ .setTicker(mContext.getString(R.string.log_access_confirmation_title))
+ .setOnlyAlertOnce(true)
+ .setAutoCancel(true);
+ mNotificationManager.notify(notificationId, notificationBuilder.build());
+ }
+
+ /**
+ * A class which watches an uid for background access and notifies the logdMonitor when
+ * the package status becomes foreground (importance change)
+ */
+ private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
+ private final int mExpectedUid;
+ private final int mExpectedGid;
+ private final int mExpectedPid;
+ private final int mExpectedFd;
+ private int mExpectedImportance;
+ private int mCurrentImportance = RunningAppProcessInfo.IMPORTANCE_GONE;
+
+ UidImportanceListener(int uid, int gid, int pid, int fd, int importance) {
+ mExpectedUid = uid;
+ mExpectedGid = gid;
+ mExpectedPid = pid;
+ mExpectedFd = fd;
+ mExpectedImportance = importance;
+ }
+
+ @Override
+ public void onUidImportance(int uid, int importance) {
+ if (uid == mExpectedUid) {
+ mCurrentImportance = importance;
+
+ /**
+ * 1) If the process status changes to foreground, send a notification
+ * for user consent.
+ * 2) If the process status remains background, we decline logd access request.
+ **/
+ if (importance <= RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE) {
+ String clientInfo = getClientInfo(uid, mExpectedGid, mExpectedPid, mExpectedFd);
+ sendNotification(0, clientInfo, uid, mExpectedGid, mExpectedPid,
+ mExpectedFd);
+ mActivityManager.removeOnUidImportanceListener(this);
+
+ synchronized (LogcatManagerService.this) {
+ sUidImportanceListenerCount--;
+ }
+ } else {
+ try {
+ getLogdService().decline(uid, mExpectedGid, mExpectedPid, mExpectedFd);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Fails to call remote functions ", ex);
+ }
+ }
+ }
+ }
+ }
+
+ private static String getClientInfo(int uid, int gid, int pid, int fd) {
+ return "UID=" + Integer.toString(uid) + " GID=" + Integer.toString(gid) + " PID="
+ + Integer.toString(pid) + " FD=" + Integer.toString(fd);
}
private class LogdMonitor implements Runnable {
@@ -74,9 +318,7 @@ public final class LogcatManagerService extends SystemService {
}
/**
- * The current version grant the permission by default.
- * And track the logd access.
- * The next version will generate a prompt for users.
+ * LogdMonitor generates a prompt for users.
* The users decide whether the logd access is allowed.
*/
@Override
@@ -86,10 +328,61 @@ public final class LogcatManagerService extends SystemService {
}
if (mStart) {
- try {
- mLogdService.approve(mUid, mGid, mPid, mFd);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Fails to call remote functions ", ex);
+
+ // TODO See the comments of ALLOWABLE_TESTING_PACKAGES.
+ if (isAllowableTestingPackage(mUid)) {
+ try {
+ getLogdService().approve(mUid, mGid, mPid, mFd);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ return;
+ }
+
+ // If the access request is coming from adb shell, approve the logd access
+ if (mUid == AID_SHELL_UID) {
+ try {
+ getLogdService().approve(mUid, mGid, mPid, mFd);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ return;
+ }
+
+ final int procState = LocalServices.getService(ActivityManagerInternal.class)
+ .getUidProcessState(mUid);
+ // If the process is foreground, send a notification for user consent
+ if (procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
+ String clientInfo = getClientInfo(mUid, mGid, mPid, mFd);
+ sendNotification(0, clientInfo, mUid, mGid, mPid, mFd);
+ } else {
+ /**
+ * If the process is background, add a background process change listener and
+ * monitor if the process status changes.
+ * To avoid clients registering multiple listeners, we limit the number of
+ * maximum listeners to MAX_UID_IMPORTANCE_COUNT_LISTENER.
+ **/
+ if (mActivityManager == null) {
+ return;
+ }
+
+ synchronized (LogcatManagerService.this) {
+ if (sUidImportanceListenerCount < MAX_UID_IMPORTANCE_COUNT_LISTENER) {
+ // Trigger addOnUidImportanceListener when there is an update from
+ // the importance of the process
+ mActivityManager.addOnUidImportanceListener(new UidImportanceListener(
+ mUid, mGid, mPid, mFd,
+ RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE),
+ RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE);
+ sUidImportanceListenerCount++;
+ } else {
+ try {
+ getLogdService().decline(mUid, mGid, mPid, mFd);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+ }
}
}
}
@@ -100,6 +393,8 @@ public final class LogcatManagerService extends SystemService {
mContext = context;
mBinderService = new BinderService();
mThreadExecutor = Executors.newCachedThreadPool();
+ mActivityManager = context.getSystemService(ActivityManager.class);
+ mNotificationManager = mContext.getSystemService(NotificationManager.class);
}
@Override
@@ -114,5 +409,4 @@ public final class LogcatManagerService extends SystemService {
private void addLogdService() {
mLogdService = ILogd.Stub.asInterface(ServiceManager.getService("logd"));
}
-
}
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 91de9e559e13..728782ccee0b 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -45,7 +45,6 @@ import android.util.SparseIntArray;
import com.android.internal.R;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -448,15 +447,16 @@ class BluetoothRouteProvider {
case BluetoothProfile.A2DP:
mA2dpProfile = (BluetoothA2dp) proxy;
// It may contain null.
- activeDevices = Collections.singletonList(mA2dpProfile.getActiveDevice());
+ activeDevices = mBluetoothAdapter.getActiveDevices(BluetoothProfile.A2DP);
break;
case BluetoothProfile.HEARING_AID:
mHearingAidProfile = (BluetoothHearingAid) proxy;
- activeDevices = mHearingAidProfile.getActiveDevices();
+ activeDevices = mBluetoothAdapter.getActiveDevices(
+ BluetoothProfile.HEARING_AID);
break;
case BluetoothProfile.LE_AUDIO:
mLeAudioProfile = (BluetoothLeAudio) proxy;
- activeDevices = mLeAudioProfile.getActiveDevices();
+ activeDevices = mBluetoothAdapter.getActiveDevices(BluetoothProfile.LE_AUDIO);
break;
default:
return;
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index 9f086e6e4a61..d745a2325b22 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -48,8 +48,8 @@ import com.android.server.SystemServerInitThreadPool;
import com.android.server.pm.dex.ArtManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
-import com.android.server.pm.pkg.SELinuxUtil;
import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.SELinuxUtil;
import dalvik.system.VMRuntime;
@@ -549,6 +549,10 @@ final class AppDataHelper {
}
public void migrateKeyStoreData(int previousAppId, int appId) {
+ // If previous UID is system UID, declaring inheritKeyStoreKeys is not supported.
+ // Silently ignore the request to migrate keys.
+ if (previousAppId == Process.SYSTEM_UID) return;
+
for (int userId : mPm.resolveUserIds(UserHandle.USER_ALL)) {
int srcUid = UserHandle.getUid(userId, previousAppId);
int destUid = UserHandle.getUid(userId, appId);
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index ba89916e6dfa..53eb9cf7d9fe 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -293,7 +293,8 @@ final class DexOptHelper {
public ArraySet<String> getOptimizablePackages() {
ArraySet<String> pkgs = new ArraySet<>();
mPm.forEachPackageState(packageState -> {
- if (mPm.mPackageDexOptimizer.canOptimizePackage(packageState.getPkg())) {
+ final AndroidPackage pkg = packageState.getPkg();
+ if (pkg != null && mPm.mPackageDexOptimizer.canOptimizePackage(pkg)) {
pkgs.add(packageState.getPackageName());
}
});
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index a5b42f03b6df..69d498794e64 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -182,7 +182,7 @@ public class PackageDexOptimizer {
mInjector = injector;
}
- boolean canOptimizePackage(AndroidPackage pkg) {
+ boolean canOptimizePackage(@NonNull AndroidPackage pkg) {
// We do not dexopt a package with no code.
// Note that the system package is marked as having no code, however we can
// still optimize it via dexoptSystemServerPath.
diff --git a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
index d455be7e4a69..46fde4b59d8b 100644
--- a/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
+++ b/services/core/java/com/android/server/pm/permission/OneTimePermissionUserManager.java
@@ -108,14 +108,18 @@ public class OneTimePermissionUserManager {
* </p>
* @param packageName The package to start a one-time permission session for
* @param timeoutMillis Number of milliseconds for an app to be in an inactive state
+ * @param revokeAfterKilledDelayMillis Number of milliseconds to wait after the process dies
+ * before ending the session. Set to -1 to use default value
+ * for the device.
* @param importanceToResetTimer The least important level to uid must be to reset the timer
* @param importanceToKeepSessionAlive The least important level the uid must be to keep the
- * session alive
+ * session alive
*
* @hide
*/
void startPackageOneTimeSession(@NonNull String packageName, long timeoutMillis,
- int importanceToResetTimer, int importanceToKeepSessionAlive) {
+ long revokeAfterKilledDelayMillis, int importanceToResetTimer,
+ int importanceToKeepSessionAlive) {
int uid;
try {
uid = mContext.getPackageManager().getPackageUid(packageName, 0);
@@ -126,11 +130,15 @@ public class OneTimePermissionUserManager {
synchronized (mLock) {
PackageInactivityListener listener = mListeners.get(uid);
- if (listener == null) {
- listener = new PackageInactivityListener(uid, packageName, timeoutMillis,
+ if (listener != null) {
+ listener.updateSessionParameters(timeoutMillis, revokeAfterKilledDelayMillis,
importanceToResetTimer, importanceToKeepSessionAlive);
- mListeners.put(uid, listener);
+ return;
}
+ listener = new PackageInactivityListener(uid, packageName, timeoutMillis,
+ revokeAfterKilledDelayMillis, importanceToResetTimer,
+ importanceToKeepSessionAlive);
+ mListeners.put(uid, listener);
}
}
@@ -159,18 +167,6 @@ public class OneTimePermissionUserManager {
}
/**
- * The delay to wait before revoking on the event an app is terminated. Recommended to be long
- * enough so that apps don't lose permission on an immediate restart
- */
- private long getKilledDelayMillis(boolean isSelfRevokedPermissionSession) {
- if (isSelfRevokedPermissionSession) {
- return 0;
- }
- return DeviceConfig.getLong(DeviceConfig.NAMESPACE_PERMISSIONS,
- PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS);
- }
-
- /**
* Register to listen for Uids being uninstalled. This must be done outside of the
* PermissionManagerService lock.
*/
@@ -178,18 +174,6 @@ public class OneTimePermissionUserManager {
mContext.registerReceiver(mUninstallListener, new IntentFilter(Intent.ACTION_UID_REMOVED));
}
- void setSelfRevokedPermissionSession(int uid) {
- synchronized (mLock) {
- PackageInactivityListener listener = mListeners.get(uid);
- if (listener == null) {
- Log.e(LOG_TAG, "Could not set session for uid " + uid
- + " as self-revoke session: session not found");
- return;
- }
- listener.setSelfRevokedPermissionSession();
- }
- }
-
/**
* A class which watches a package for inactivity and notifies the permission controller when
* the package becomes inactive
@@ -200,11 +184,11 @@ public class OneTimePermissionUserManager {
private final int mUid;
private final @NonNull String mPackageName;
- private final long mTimeout;
- private final int mImportanceToResetTimer;
- private final int mImportanceToKeepSessionAlive;
+ private long mTimeout;
+ private long mRevokeAfterKilledDelay;
+ private int mImportanceToResetTimer;
+ private int mImportanceToKeepSessionAlive;
- private boolean mIsSelfRevokedPermissionSession;
private boolean mIsAlarmSet;
private boolean mIsFinished;
@@ -218,16 +202,23 @@ public class OneTimePermissionUserManager {
private final Object mToken = new Object();
private PackageInactivityListener(int uid, @NonNull String packageName, long timeout,
- int importanceToResetTimer, int importanceToKeepSessionAlive) {
+ long revokeAfterkilledDelay, int importanceToResetTimer,
+ int importanceToKeepSessionAlive) {
Log.i(LOG_TAG,
"Start tracking " + packageName + ". uid=" + uid + " timeout=" + timeout
+ + " killedDelay=" + revokeAfterkilledDelay
+ " importanceToResetTimer=" + importanceToResetTimer
+ " importanceToKeepSessionAlive=" + importanceToKeepSessionAlive);
mUid = uid;
mPackageName = packageName;
mTimeout = timeout;
+ mRevokeAfterKilledDelay = revokeAfterkilledDelay == -1
+ ? DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PERMISSIONS, PROPERTY_KILLED_DELAY_CONFIG_KEY,
+ DEFAULT_KILLED_DELAY_MILLIS)
+ : revokeAfterkilledDelay;
mImportanceToResetTimer = importanceToResetTimer;
mImportanceToKeepSessionAlive = importanceToKeepSessionAlive;
@@ -247,6 +238,28 @@ public class OneTimePermissionUserManager {
onImportanceChanged(mUid, mActivityManager.getPackageImportance(packageName));
}
+ public void updateSessionParameters(long timeoutMillis, long revokeAfterKilledDelayMillis,
+ int importanceToResetTimer, int importanceToKeepSessionAlive) {
+ synchronized (mInnerLock) {
+ mTimeout = Math.min(mTimeout, timeoutMillis);
+ mRevokeAfterKilledDelay = Math.min(mRevokeAfterKilledDelay,
+ revokeAfterKilledDelayMillis == -1
+ ? DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_PERMISSIONS,
+ PROPERTY_KILLED_DELAY_CONFIG_KEY, DEFAULT_KILLED_DELAY_MILLIS)
+ : revokeAfterKilledDelayMillis);
+ mImportanceToResetTimer = Math.min(importanceToResetTimer, mImportanceToResetTimer);
+ mImportanceToKeepSessionAlive = Math.min(importanceToKeepSessionAlive,
+ mImportanceToKeepSessionAlive);
+ Log.v(LOG_TAG,
+ "Updated params for " + mPackageName + ". timeout=" + mTimeout
+ + " killedDelay=" + mRevokeAfterKilledDelay
+ + " importanceToResetTimer=" + mImportanceToResetTimer
+ + " importanceToKeepSessionAlive=" + mImportanceToKeepSessionAlive);
+ onImportanceChanged(mUid, mActivityManager.getPackageImportance(mPackageName));
+ }
+ }
+
private void onImportanceChanged(int uid, int importance) {
if (uid != mUid) {
return;
@@ -271,7 +284,7 @@ public class OneTimePermissionUserManager {
}
onImportanceChanged(mUid, imp);
}
- }, mToken, getKilledDelayMillis(mIsSelfRevokedPermissionSession));
+ }, mToken, mRevokeAfterKilledDelay);
return;
}
if (importance > mImportanceToResetTimer) {
@@ -307,14 +320,6 @@ public class OneTimePermissionUserManager {
}
/**
- * Marks the session as a self-revoke session, which does not delay the revocation when
- * the app is restarting.
- */
- public void setSelfRevokedPermissionSession() {
- mIsSelfRevokedPermissionSession = true;
- }
-
- /**
* Set the alarm which will callback when the package is inactive
*/
@GuardedBy("mInnerLock")
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index edc0e3d64c42..695d6dd0bc76 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -68,7 +68,6 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.TriFunction;
import com.android.server.LocalServices;
@@ -388,7 +387,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void startOneTimePermissionSession(String packageName, @UserIdInt int userId,
- long timeoutMillis, int importanceToResetTimer, int importanceToKeepSessionAlive) {
+ long timeoutMillis, long revokeAfterKilledDelayMillis, int importanceToResetTimer,
+ int importanceToKeepSessionAlive) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS,
"Must hold " + Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS
@@ -398,7 +398,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
final long token = Binder.clearCallingIdentity();
try {
getOneTimePermissionUserManager(userId).startPackageOneTimeSession(packageName,
- timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
+ timeoutMillis, revokeAfterKilledDelayMillis, importanceToResetTimer,
+ importanceToKeepSessionAlive);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -563,16 +564,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
@Override
public void revokeOwnPermissionsOnKill(@NonNull String packageName,
@NonNull List<String> permissions) {
- final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getUserId(callingUid);
- AndroidFuture<Void> future = new AndroidFuture<>();
- future.whenComplete((result, err) -> {
- if (err == null) {
- getOneTimePermissionUserManager(callingUserId)
- .setSelfRevokedPermissionSession(callingUid);
- }
- });
- mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions, future);
+ mPermissionManagerServiceImpl.revokeOwnPermissionsOnKill(packageName, permissions);
}
@Override
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index db9c1b56e4d8..ed351fd4aef9 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -108,7 +108,6 @@ import android.util.SparseBooleanArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.compat.IPlatformCompat;
-import com.android.internal.infra.AndroidFuture;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.os.RoSystemProperties;
@@ -1592,8 +1591,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
}
@Override
- public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions,
- AndroidFuture<Void> callback) {
+ public void revokeOwnPermissionsOnKill(String packageName, List<String> permissions) {
final int callingUid = Binder.getCallingUid();
int callingUserId = UserHandle.getUserId(callingUid);
int targetPackageUid = mPackageManagerInt.getPackageUid(packageName, 0, callingUserId);
@@ -1608,8 +1606,7 @@ public class PermissionManagerServiceImpl implements PermissionManagerServiceInt
+ permName + " because it does not hold that permission");
}
}
- mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions,
- callback);
+ mPermissionControllerManager.revokeOwnPermissionsOnKill(packageName, permissions);
}
private boolean mayManageRolePermission(int uid) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 91c558b2f35e..3e28320a2130 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -27,7 +27,6 @@ import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.permission.IOnPermissionsChangeListener;
import android.permission.PermissionManagerInternal;
-import com.android.internal.infra.AndroidFuture;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.FileDescriptor;
@@ -338,16 +337,16 @@ public interface PermissionManagerServiceInterface extends PermissionManagerInte
* <li>Each permission in {@code permissions} must be a runtime permission.
* </ul>
* <p>
- * For every permission in {@code permissions}, the entire permission group it belongs to will
- * be revoked. This revocation happens asynchronously and kills all processes running in the
- * same UID as {@code packageName}. It will be triggered once it is safe to do so.
+ * Background permissions which have no corresponding foreground permission still granted once
+ * the revocation is effective will also be revoked.
+ * <p>
+ * This revocation happens asynchronously and kills all processes running in the same UID as
+ * {@code packageName}. It will be triggered once it is safe to do so.
*
* @param packageName The name of the package for which the permissions will be revoked.
* @param permissions List of permissions to be revoked.
- * @param callback Callback called when the revocation request has been completed.
*/
- void revokeOwnPermissionsOnKill(String packageName, List<String> permissions,
- AndroidFuture<Void> callback);
+ void revokeOwnPermissionsOnKill(String packageName, List<String> permissions);
/**
* Get whether you should show UI with rationale for requesting a permission. You should do this
diff --git a/services/core/java/com/android/server/security/AttestationVerificationManagerService.java b/services/core/java/com/android/server/security/AttestationVerificationManagerService.java
index f519ceda1e50..243efb5e58ce 100644
--- a/services/core/java/com/android/server/security/AttestationVerificationManagerService.java
+++ b/services/core/java/com/android/server/security/AttestationVerificationManagerService.java
@@ -16,6 +16,8 @@
package com.android.server.security;
+import static android.security.attestationverification.AttestationVerificationManager.PROFILE_SELF_TRUSTED;
+import static android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE;
import static android.security.attestationverification.AttestationVerificationManager.RESULT_UNKNOWN;
import android.content.Context;
@@ -76,10 +78,24 @@ public class AttestationVerificationManagerService extends SystemService {
private void verifyAttestationForAllVerifiers(
AttestationProfile profile, int localBindingType, Bundle requirements,
byte[] attestation, AndroidFuture<IVerificationResult> resultCallback) {
- // TODO(b/201696614): Implement
IVerificationResult result = new IVerificationResult();
- result.resultCode = RESULT_UNKNOWN;
+ // TODO(b/201696614): Implement
result.token = null;
+ switch (profile.getAttestationProfileId()) {
+ case PROFILE_SELF_TRUSTED:
+ Slog.d(TAG, "Verifying Self trusted profile.");
+ try {
+ result.resultCode =
+ AttestationVerificationSelfTrustedVerifierForTesting.getInstance()
+ .verifyAttestation(localBindingType, requirements, attestation);
+ } catch (Throwable t) {
+ result.resultCode = RESULT_FAILURE;
+ }
+ break;
+ default:
+ Slog.d(TAG, "No profile found, defaulting.");
+ result.resultCode = RESULT_UNKNOWN;
+ }
resultCallback.complete(result);
}
diff --git a/services/core/java/com/android/server/security/AttestationVerificationSelfTrustedVerifierForTesting.java b/services/core/java/com/android/server/security/AttestationVerificationSelfTrustedVerifierForTesting.java
new file mode 100644
index 000000000000..58df2bd982dc
--- /dev/null
+++ b/services/core/java/com/android/server/security/AttestationVerificationSelfTrustedVerifierForTesting.java
@@ -0,0 +1,224 @@
+/*
+ * 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 com.android.server.security;
+
+import static android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE;
+import static android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE;
+import static android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS;
+import static android.security.attestationverification.AttestationVerificationManager.TYPE_CHALLENGE;
+
+import android.annotation.NonNull;
+import android.os.Build;
+import android.os.Bundle;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
+import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.android.internal.org.bouncycastle.asn1.ASN1OctetString;
+import com.android.internal.org.bouncycastle.asn1.ASN1Sequence;
+import com.android.internal.org.bouncycastle.asn1.x509.Certificate;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Verifies {@code PROFILE_SELF_TRUSTED} attestations.
+ *
+ * Verifies that the attesting environment can create an attestation with the same root certificate
+ * as the verifying device with a matching attestation challenge. Skips CRL revocations checking
+ * so this verifier can work in a hermetic test environment.
+ *
+ * This verifier profile is intended to be used only for testing.
+ */
+class AttestationVerificationSelfTrustedVerifierForTesting {
+ private static final String TAG = "AVF";
+ private static final boolean DEBUG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.VERBOSE);
+
+ // The OID for the extension Android Keymint puts into device-generated certificates.
+ private static final String ANDROID_KEYMINT_KEY_DESCRIPTION_EXTENSION_OID =
+ "1.3.6.1.4.1.11129.2.1.17";
+
+ // ASN.1 sequence index values for the Android Keymint extension.
+ private static final int ATTESTATION_CHALLENGE_INDEX = 4;
+
+ private static final String ANDROID_KEYSTORE = "AndroidKeyStore";
+ private static final String GOLDEN_ALIAS =
+ AttestationVerificationSelfTrustedVerifierForTesting.class.getCanonicalName()
+ + ".Golden";
+
+ private static volatile AttestationVerificationSelfTrustedVerifierForTesting
+ sAttestationVerificationSelfTrustedVerifier = null;
+
+ private final CertificateFactory mCertificateFactory;
+ private final CertPathValidator mCertPathValidator;
+ private final KeyStore mAndroidKeyStore;
+ private X509Certificate mGoldenRootCert;
+
+ static AttestationVerificationSelfTrustedVerifierForTesting getInstance()
+ throws Exception {
+ if (sAttestationVerificationSelfTrustedVerifier == null) {
+ synchronized (AttestationVerificationSelfTrustedVerifierForTesting.class) {
+ if (sAttestationVerificationSelfTrustedVerifier == null) {
+ sAttestationVerificationSelfTrustedVerifier =
+ new AttestationVerificationSelfTrustedVerifierForTesting();
+ }
+ }
+ }
+ return sAttestationVerificationSelfTrustedVerifier;
+ }
+
+ private static void debugVerboseLog(String str, Throwable t) {
+ if (DEBUG) {
+ Slog.v(TAG, str, t);
+ }
+ }
+
+ private static void debugVerboseLog(String str) {
+ if (DEBUG) {
+ Slog.v(TAG, str);
+ }
+ }
+
+ private AttestationVerificationSelfTrustedVerifierForTesting() throws Exception {
+ mCertificateFactory = CertificateFactory.getInstance("X.509");
+ mCertPathValidator = CertPathValidator.getInstance("PKIX");
+ mAndroidKeyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
+ mAndroidKeyStore.load(null);
+ if (!mAndroidKeyStore.containsAlias(GOLDEN_ALIAS)) {
+ KeyPairGenerator kpg =
+ KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, ANDROID_KEYSTORE);
+ KeyGenParameterSpec parameterSpec = new KeyGenParameterSpec.Builder(
+ GOLDEN_ALIAS, KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+ .setAttestationChallenge(GOLDEN_ALIAS.getBytes())
+ .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512).build();
+ kpg.initialize(parameterSpec);
+ kpg.generateKeyPair();
+ }
+
+ X509Certificate[] goldenCerts = (X509Certificate[])
+ ((KeyStore.PrivateKeyEntry) mAndroidKeyStore.getEntry(GOLDEN_ALIAS, null))
+ .getCertificateChain();
+ mGoldenRootCert = goldenCerts[goldenCerts.length - 1];
+ }
+
+ int verifyAttestation(
+ int localBindingType, @NonNull Bundle requirements, @NonNull byte[] attestation) {
+ List<X509Certificate> certificates = new ArrayList<>();
+ ByteArrayInputStream bis = new ByteArrayInputStream(attestation);
+ try {
+ while (bis.available() > 0) {
+ certificates.add((X509Certificate) mCertificateFactory.generateCertificate(bis));
+ }
+ } catch (CertificateException e) {
+ debugVerboseLog("Unable to parse certificates from attestation", e);
+ return RESULT_FAILURE;
+ }
+
+ if (localBindingType == TYPE_CHALLENGE
+ && validateRequirements(requirements)
+ && checkLeafChallenge(requirements, certificates)
+ && verifyCertificateChain(certificates)) {
+ return RESULT_SUCCESS;
+ }
+
+ return RESULT_FAILURE;
+ }
+
+ private boolean verifyCertificateChain(List<X509Certificate> certificates) {
+ if (certificates.size() < 2) {
+ debugVerboseLog("Certificate chain less than 2 in size.");
+ return false;
+ }
+
+ try {
+ CertPath certificatePath = mCertificateFactory.generateCertPath(certificates);
+ PKIXParameters validationParams = new PKIXParameters(getTrustAnchors());
+ // Skipping revocation checking because we want this to work in a hermetic test
+ // environment.
+ validationParams.setRevocationEnabled(false);
+ mCertPathValidator.validate(certificatePath, validationParams);
+ } catch (Throwable t) {
+ debugVerboseLog("Invalid certificate chain", t);
+ return false;
+ }
+
+ return true;
+ }
+
+ private Set<TrustAnchor> getTrustAnchors() {
+ return Collections.singleton(new TrustAnchor(mGoldenRootCert, null));
+ }
+
+ private boolean validateRequirements(Bundle requirements) {
+ if (requirements.size() != 1) {
+ debugVerboseLog("Requirements does not contain exactly 1 key.");
+ return false;
+ }
+ if (!requirements.containsKey(PARAM_CHALLENGE)) {
+ debugVerboseLog("Requirements does not contain key: " + PARAM_CHALLENGE);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean checkLeafChallenge(Bundle requirements, List<X509Certificate> certificates) {
+ // Verify challenge
+ byte[] challenge;
+ try {
+ challenge = getChallengeFromCert(certificates.get(0));
+ } catch (Throwable t) {
+ debugVerboseLog("Unable to parse challenge from certificate.", t);
+ return false;
+ }
+
+ if (Arrays.equals(requirements.getByteArray(PARAM_CHALLENGE), challenge)) {
+ return true;
+ } else {
+ debugVerboseLog("Self-Trusted validation failed; challenge mismatch.");
+ return false;
+ }
+ }
+
+ private byte[] getChallengeFromCert(@NonNull X509Certificate x509Certificate)
+ throws CertificateEncodingException, IOException {
+ Certificate certificate = Certificate.getInstance(
+ new ASN1InputStream(x509Certificate.getEncoded()).readObject());
+ ASN1Sequence keyAttributes = (ASN1Sequence) certificate.getTBSCertificate().getExtensions()
+ .getExtensionParsedValue(
+ new ASN1ObjectIdentifier(ANDROID_KEYMINT_KEY_DESCRIPTION_EXTENSION_OID));
+ return ((ASN1OctetString) keyAttributes.getObjectAt(ATTESTATION_CHALLENGE_INDEX))
+ .getOctets();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 5f04b7e2621a..6836e315437c 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7655,13 +7655,15 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* <li>{@link LetterboxConfiguration#getIsEducationEnabled} is true.
* <li>The activity is eligible for fixed orientation letterbox.
* <li>The activity is in fullscreen.
+ * <li>The activity is portrait-only.
* </ul>
*/
// TODO(b/215316431): Add tests
boolean isEligibleForLetterboxEducation() {
return mWmService.mLetterboxConfiguration.getIsEducationEnabled()
&& mIsEligibleForFixedOrientationLetterbox
- && getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
+ && getWindowingMode() == WINDOWING_MODE_FULLSCREEN
+ && getRequestedConfigurationOrientation() == ORIENTATION_PORTRAIT;
}
/**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 8d4ae908e79f..ca4d7178fbcc 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -24,6 +24,7 @@ import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS;
+import static android.Manifest.permission.MANAGE_GAME_ACTIVITY;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REMOVE_TASKS;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
@@ -1771,6 +1772,43 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
+ public int startActivityFromGameSession(IApplicationThread caller, String callingPackage,
+ String callingFeatureId, int callingPid, int callingUid, Intent intent, int taskId,
+ int userId) {
+ if (checkCallingPermission(MANAGE_GAME_ACTIVITY) != PERMISSION_GRANTED) {
+ final String msg = "Permission Denial: startActivityFromGameSession() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + MANAGE_GAME_ACTIVITY;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ assertPackageMatchesCallingUid(callingPackage);
+
+ final ActivityOptions activityOptions = ActivityOptions.makeBasic();
+ activityOptions.setLaunchTaskId(taskId);
+
+ userId = handleIncomingUser(callingPid, callingUid, userId, "startActivityFromGameSession");
+
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ return getActivityStartController()
+ .obtainStarter(intent, "startActivityFromGameSession")
+ .setCaller(caller)
+ .setCallingUid(callingUid)
+ .setCallingPid(callingPid)
+ .setCallingPackage(intent.getPackage())
+ .setCallingFeatureId(callingFeatureId)
+ .setUserId(userId)
+ .setActivityOptions(activityOptions.toBundle())
+ .setRealCallingUid(Binder.getCallingUid())
+ .execute();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
public BackNavigationInfo startBackNavigation() {
mAmInternal.enforceCallingPermission(START_TASKS_FROM_RECENTS,
"startBackNavigation()");
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index a8779fa79675..45a6cb9d3920 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -29,6 +29,7 @@ import android.os.SystemProperties;
import android.util.Slog;
import android.view.SurfaceControl;
import android.window.BackNavigationInfo;
+import android.window.IOnBackInvokedCallback;
import android.window.TaskSnapshot;
import com.android.internal.annotations.VisibleForTesting;
@@ -91,29 +92,41 @@ class BackNavigationController {
HardwareBuffer screenshotBuffer = null;
int prevTaskId;
int prevUserId;
+ IOnBackInvokedCallback callback;
synchronized (task.mWmService.mGlobalLock) {
activityRecord = task.topRunningActivity();
removedWindowContainer = activityRecord;
taskWindowConfiguration = task.getTaskInfo().configuration.windowConfiguration;
- ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, topRunningActivity=%s",
- task, activityRecord);
-
- // IME is visible, back gesture will dismiss it, nothing to preview.
- if (task.getDisplayContent().getImeContainer().isVisible()) {
- return null;
- }
-
- // Current Activity is home, there is no previous activity to display
- if (activityRecord.isActivityTypeHome()) {
- return null;
+ WindowState topChild = activityRecord.getTopChild();
+ callback = topChild.getOnBackInvokedCallback();
+
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "startBackNavigation task=%s, "
+ + "topRunningActivity=%s, topWindow=%s backCallback=%s",
+ task, activityRecord, topChild,
+ callback != null ? callback.getClass().getSimpleName() : null);
+
+ // For IME and Home, either a callback is registered, or we do nothing. In both cases,
+ // we don't need to pass the leashes below.
+ if (task.getDisplayContent().getImeContainer().isVisible()
+ || activityRecord.isActivityTypeHome()) {
+ if (callback != null) {
+ return new BackNavigationInfo(BackNavigationInfo.TYPE_CALLBACK,
+ null /* topWindowLeash */, null /* screenshotSurface */,
+ null /* screenshotBuffer */, null /* taskWindowConfiguration */,
+ null /* onBackNavigationDone */, callback /* onBackInvokedCallback */);
+ } else {
+ return null;
+ }
}
prev = task.getActivity(
(r) -> !r.finishing && r.getTask() == task && !r.isTopRunningActivity());
- if (prev != null) {
+ if (callback != null) {
+ backType = BackNavigationInfo.TYPE_CALLBACK;
+ } else if (prev != null) {
backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
} else if (task.returnsToHomeRootTask()) {
prevTask = null;
@@ -148,7 +161,7 @@ class BackNavigationController {
// Prepare a leash to animate the current top window
animLeash = removedWindowContainer.makeAnimationLeash()
- .setName("BackPreview Leash")
+ .setName("BackPreview Leash for " + removedWindowContainer)
.setHidden(false)
.setBLASTLayer()
.build();
@@ -158,7 +171,7 @@ class BackNavigationController {
}
SurfaceControl.Builder builder = new SurfaceControl.Builder()
- .setName("BackPreview Screenshot")
+ .setName("BackPreview Screenshot for " + prev)
.setParent(animationLeashParent)
.setHidden(false)
.setBLASTLayer();
@@ -171,6 +184,10 @@ class BackNavigationController {
screenshotBuffer = getTaskSnapshot(prevTaskId, prevUserId);
}
}
+
+ // The Animation leash needs to be above the screenshot surface, but the animation leash
+ // needs to be added before to be in the synchronized block.
+ tx.setLayer(animLeash, 1);
tx.apply();
WindowContainer<?> finalRemovedWindowContainer = removedWindowContainer;
@@ -183,13 +200,16 @@ class BackNavigationController {
return null;
}
+ RemoteCallback onBackNavigationDone = new RemoteCallback(
+ result -> resetSurfaces(finalRemovedWindowContainer
+ ));
return new BackNavigationInfo(backType,
animLeash,
screenshotSurface,
screenshotBuffer,
taskWindowConfiguration,
- new RemoteCallback(result -> resetSurfaces(finalRemovedWindowContainer
- )));
+ onBackNavigationDone,
+ callback);
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 2ae2b4370522..f26c53938077 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -885,8 +885,16 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
}
@Override
- public void setOnBackInvokedCallback(IWindow iWindow,
- IOnBackInvokedCallback iOnBackInvokedCallback) throws RemoteException {
- // TODO: Set the callback to the WindowState of the window.
+ public void setOnBackInvokedCallback(IWindow window,
+ IOnBackInvokedCallback onBackInvokedCallback) throws RemoteException {
+ synchronized (mService.mGlobalLock) {
+ WindowState windowState = mService.windowForClientLocked(this, window, false);
+ if (windowState == null) {
+ Slog.e(TAG_WM,
+ "setOnBackInvokedCallback(): Can't find window state for window:" + window);
+ } else {
+ windowState.setOnBackInvokedCallback(onBackInvokedCallback);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 97735a29b027..b84ef773f85a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2197,10 +2197,6 @@ class Task extends TaskFragment {
final Rect taskBounds = getBounds();
width = taskBounds.width();
height = taskBounds.height();
-
- final int outset = getTaskOutset();
- width += 2 * outset;
- height += 2 * outset;
}
if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
return;
@@ -2209,28 +2205,6 @@ class Task extends TaskFragment {
mLastSurfaceSize.set(width, height);
}
- /**
- * Calculate an amount by which to expand the task bounds in each direction.
- * Used to make room for shadows in the pinned windowing mode.
- */
- int getTaskOutset() {
- // If we are drawing shadows on the task then don't outset the root task.
- if (mWmService.mRenderShadowsInCompositor) {
- return 0;
- }
- DisplayContent displayContent = getDisplayContent();
- if (inPinnedWindowingMode() && displayContent != null) {
- final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
-
- // We multiply by two to match the client logic for converting view elevation
- // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets}
- return (int) Math.ceil(
- mWmService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, displayMetrics)
- * 2);
- }
- return 0;
- }
-
@VisibleForTesting
Point getLastSurfaceSize() {
return mLastSurfaceSize;
@@ -4338,7 +4312,7 @@ class Task extends TaskFragment {
*/
private void updateShadowsRadius(boolean taskIsFocused,
SurfaceControl.Transaction pendingTransaction) {
- if (!mWmService.mRenderShadowsInCompositor || !isRootTask()) return;
+ if (!isRootTask()) return;
final float newShadowRadius = getShadowRadius(taskIsFocused);
if (mShadowRadius != newShadowRadius) {
@@ -6015,14 +5989,6 @@ class Task extends TaskFragment {
scheduleAnimation();
}
- @Override
- void getRelativePosition(Point outPos) {
- super.getRelativePosition(outPos);
- final int outset = getTaskOutset();
- outPos.x -= outset;
- outPos.y -= outset;
- }
-
private Point getRelativePosition() {
Point position = new Point();
getRelativePosition(position);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 1167cb531c76..22c430ff8016 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -462,11 +462,6 @@ public class WindowManagerService extends IWindowManager.Stub
int mVr2dDisplayId = INVALID_DISPLAY;
boolean mVrModeEnabled = false;
- /* If true, shadows drawn around the window will be rendered by the system compositor. If
- * false, shadows will be drawn by the client by setting an elevation on the root view and
- * the contents will be inset by the shadow radius. */
- boolean mRenderShadowsInCompositor = false;
-
/**
* Tracks a map of input tokens to info that is used to decide whether to intercept
* a key event.
@@ -811,8 +806,6 @@ public class WindowManagerService extends IWindowManager.Stub
resolver.registerContentObserver(mForceResizableUri, false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(mDevEnableNonResizableMultiWindowUri, false, this,
UserHandle.USER_ALL);
- resolver.registerContentObserver(mRenderShadowsInCompositorUri, false, this,
- UserHandle.USER_ALL);
resolver.registerContentObserver(mDisplaySettingsPathUri, false, this,
UserHandle.USER_ALL);
}
@@ -853,11 +846,6 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- if (mRenderShadowsInCompositorUri.equals(uri)) {
- setShadowRenderer();
- return;
- }
-
if (mDisplaySettingsPathUri.equals(uri)) {
updateDisplaySettingsLocation();
return;
@@ -972,11 +960,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- private void setShadowRenderer() {
- mRenderShadowsInCompositor = Settings.Global.getInt(mContext.getContentResolver(),
- DEVELOPMENT_RENDER_SHADOWS_IN_COMPOSITOR, 1) != 0;
- }
-
PowerManager mPowerManager;
PowerManagerInternal mPowerManagerInternal;
@@ -1395,7 +1378,6 @@ public class WindowManagerService extends IWindowManager.Stub
float[] spotColor = {0.f, 0.f, 0.f, spotShadowAlpha};
SurfaceControl.setGlobalShadowSettings(ambientColor, spotColor, lightY, lightZ,
lightRadius);
- setShadowRenderer();
}
/**
@@ -3855,14 +3837,20 @@ public class WindowManagerService extends IWindowManager.Stub
}
/**
- * Generates and returns an up-to-date {@link Bitmap} for the specified taskId. The returned
- * bitmap will be full size and will not include any secure content.
+ * Generates and returns an up-to-date {@link Bitmap} for the specified taskId.
*
- * @param taskId The task ID of the task for which a snapshot is requested.
+ * @param taskId The task ID of the task for which a Bitmap is requested.
+ * @param layerCaptureArgsBuilder A {@link SurfaceControl.LayerCaptureArgs.Builder} with
+ * arguments for how to capture the Bitmap. The caller can
+ * specify any arguments, but this method will ensure that the
+ * specified task's SurfaceControl is used and the crop is set to
+ * the bounds of that task.
* @return The Bitmap, or null if no task with the specified ID can be found or the bitmap could
* not be generated.
*/
- @Nullable public Bitmap captureTaskBitmap(int taskId) {
+ @Nullable
+ public Bitmap captureTaskBitmap(int taskId,
+ @NonNull SurfaceControl.LayerCaptureArgs.Builder layerCaptureArgsBuilder) {
if (mTaskSnapshotController.shouldDisableSnapshots()) {
return null;
}
@@ -3876,9 +3864,7 @@ public class WindowManagerService extends IWindowManager.Stub
task.getBounds(mTmpRect);
final SurfaceControl sc = task.getSurfaceControl();
final SurfaceControl.ScreenshotHardwareBuffer buffer = SurfaceControl.captureLayers(
- new SurfaceControl.LayerCaptureArgs.Builder(sc)
- .setSourceCrop(mTmpRect)
- .build());
+ layerCaptureArgsBuilder.setLayer(sc).setSourceCrop(mTmpRect).build());
if (buffer == null) {
Slog.w(TAG, "Could not get screenshot buffer for taskId: " + taskId);
return null;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 79c64b19882d..0d72e9a567bc 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -106,6 +106,7 @@ import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BACK_PREVIEW;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
@@ -245,6 +246,7 @@ import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.window.ClientWindowFrames;
+import android.window.IOnBackInvokedCallback;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.KeyInterceptionInfo;
@@ -845,6 +847,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
};
+ /**
+ * @see #setOnBackInvokedCallback(IOnBackInvokedCallback)
+ */
+ private IOnBackInvokedCallback mOnBackInvokedCallback;
+
@Override
WindowState asWindowState() {
return this;
@@ -1061,6 +1068,22 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return true;
}
+ /**
+ * Used by {@link android.window.WindowOnBackInvokedDispatcher} to set the callback to be
+ * called when a back navigation action is initiated.
+ * @see BackNavigationController
+ */
+ void setOnBackInvokedCallback(@Nullable IOnBackInvokedCallback onBackInvokedCallback) {
+ ProtoLog.d(WM_DEBUG_BACK_PREVIEW, "%s: Setting back callback %s",
+ this, onBackInvokedCallback);
+ mOnBackInvokedCallback = onBackInvokedCallback;
+ }
+
+ @Nullable
+ IOnBackInvokedCallback getOnBackInvokedCallback() {
+ return mOnBackInvokedCallback;
+ }
+
interface PowerManagerWrapper {
void wakeUp(long time, @WakeReason int reason, String details);
@@ -5398,17 +5421,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
outPoint.offset(-parentBounds.left, -parentBounds.top);
}
- Task rootTask = getRootTask();
-
- // If we have root task outsets, that means the top-left
- // will be outset, and we need to inset ourselves
- // to account for it. If we actually have shadows we will
- // then un-inset ourselves by the surfaceInsets.
- if (rootTask != null) {
- final int outset = rootTask.getTaskOutset();
- outPoint.offset(outset, outset);
- }
-
// The surface size is larger than the window if the window has positive surface insets.
transformSurfaceInsetsPosition(mTmpPoint, mAttrs.surfaceInsets);
outPoint.offset(-mTmpPoint.x, -mTmpPoint.y);
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 8cb27e179c19..e5529f1997a3 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -265,7 +265,6 @@ public:
base::Result<std::unique_ptr<InputChannel>> createInputChannel(JNIEnv* env,
const std::string& name);
base::Result<std::unique_ptr<InputChannel>> createInputMonitor(JNIEnv* env, int32_t displayId,
- bool isGestureMonitor,
const std::string& name,
int32_t pid);
status_t removeInputChannel(JNIEnv* env, const sp<IBinder>& connectionToken);
@@ -522,11 +521,9 @@ base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputChann
}
base::Result<std::unique_ptr<InputChannel>> NativeInputManager::createInputMonitor(
- JNIEnv* /* env */, int32_t displayId, bool isGestureMonitor, const std::string& name,
- int32_t pid) {
+ JNIEnv* /* env */, int32_t displayId, const std::string& name, int32_t pid) {
ATRACE_CALL();
- return mInputManager->getDispatcher().createInputMonitor(displayId, isGestureMonitor, name,
- pid);
+ return mInputManager->getDispatcher().createInputMonitor(displayId, name, pid);
}
status_t NativeInputManager::removeInputChannel(JNIEnv* /* env */,
@@ -1659,7 +1656,7 @@ static jobject nativeCreateInputChannel(JNIEnv* env, jclass /* clazz */, jlong p
}
static jobject nativeCreateInputMonitor(JNIEnv* env, jclass /* clazz */, jlong ptr, jint displayId,
- jboolean isGestureMonitor, jstring nameObj, jint pid) {
+ jstring nameObj, jint pid) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
if (displayId == ADISPLAY_ID_NONE) {
@@ -1672,7 +1669,7 @@ static jobject nativeCreateInputMonitor(JNIEnv* env, jclass /* clazz */, jlong p
std::string name = nameChars.c_str();
base::Result<std::unique_ptr<InputChannel>> inputChannel =
- im->createInputMonitor(env, displayId, isGestureMonitor, name, pid);
+ im->createInputMonitor(env, displayId, name, pid);
if (!inputChannel.ok()) {
std::string message = inputChannel.error().message();
@@ -2381,7 +2378,7 @@ static const JNINativeMethod gInputManagerMethods[] = {
{"nativeGetKeyCodeForKeyLocation", "(JII)I", (void*)nativeGetKeyCodeForKeyLocation},
{"nativeCreateInputChannel", "(JLjava/lang/String;)Landroid/view/InputChannel;",
(void*)nativeCreateInputChannel},
- {"nativeCreateInputMonitor", "(JIZLjava/lang/String;I)Landroid/view/InputChannel;",
+ {"nativeCreateInputMonitor", "(JILjava/lang/String;I)Landroid/view/InputChannel;",
(void*)nativeCreateInputMonitor},
{"nativeRemoveInputChannel", "(JLandroid/os/IBinder;)V", (void*)nativeRemoveInputChannel},
{"nativePilferPointers", "(JLandroid/os/IBinder;)V", (void*)nativePilferPointers},
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 166a0f5272cf..0584604ac7b9 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -509,7 +509,7 @@ uint32_t GnssCallback::getConstellationType(
template <class T_list, class T_sv_info>
Return<void> GnssCallback::gnssSvStatusCbImpl(const T_list& svStatus) {
// In HIDL or AIDL v1, if no listener is registered, do not report svInfoList to the framework.
- if (gnssHalAidl == nullptr || gnssHalAidl->getInterfaceVersion() == 1) {
+ if (gnssHalAidl == nullptr || gnssHalAidl->getInterfaceVersion() <= 1) {
if (!isSvStatusRegistered) {
return Void();
}
@@ -695,7 +695,7 @@ Status GnssCallbackAidl::gnssLocationCb(const GnssLocationAidl& location) {
Status GnssCallbackAidl::gnssNmeaCb(const int64_t timestamp, const std::string& nmea) {
// In AIDL v1, if no listener is registered, do not report nmea to the framework.
- if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() == 1) {
+ if (gnssHalAidl != nullptr && gnssHalAidl->getInterfaceVersion() <= 1) {
if (!isNmeaRegistered) {
return Status::ok();
}
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 79d80366efd3..be0ddc155ae0 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -123,6 +123,18 @@
<xs:annotation name="nonnull"/>
<xs:annotation name="final"/>
</xs:element>
+ <!-- The minimum HDR video size at which high-brightness-mode is allowed to operate.
+ Default is 0.5 if not specified-->
+ <xs:element name="minimumHdrPercentOfScreen" type="nonNegativeDecimal"
+ minOccurs="0" maxOccurs="1">
+ <xs:annotation name="nullable"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <!-- This LUT specifies how to boost HDR brightness at given SDR brightness (nits). -->
+ <xs:element type="sdrHdrRatioMap" name="sdrHdrRatioMap" minOccurs="0" maxOccurs="1">
+ <xs:annotation name="nullable"/>
+ <xs:annotation name="final"/>
+ </xs:element>
</xs:all>
<xs:attribute name="enabled" type="xs:boolean" use="optional"/>
</xs:complexType>
@@ -158,6 +170,14 @@
</xs:restriction>
</xs:simpleType>
+ <!-- Maps to DisplayDeviceConfig.INTERPOLATION_* values. -->
+ <xs:simpleType name="interpolation">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="default"/>
+ <xs:enumeration value="linear"/>
+ </xs:restriction>
+ </xs:simpleType>
+
<xs:complexType name="thermalThrottling">
<xs:complexType>
<xs:element type="brightnessThrottlingMap" name="brightnessThrottlingMap">
@@ -196,6 +216,7 @@
<xs:annotation name="final"/>
</xs:element>
</xs:sequence>
+ <xs:attribute name="interpolation" type="interpolation" use="optional"/>
</xs:complexType>
<xs:complexType name="point">
@@ -211,6 +232,28 @@
</xs:sequence>
</xs:complexType>
+ <xs:complexType name="sdrHdrRatioMap">
+ <xs:sequence>
+ <xs:element name="point" type="sdrHdrRatioPoint" maxOccurs="unbounded" minOccurs="2">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="sdrHdrRatioPoint">
+ <xs:sequence>
+ <xs:element type="nonNegativeDecimal" name="sdrNits">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element type="nonNegativeDecimal" name="hdrRatio">
+ <xs:annotation name="nonnull"/>
+ <xs:annotation name="final"/>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
<xs:simpleType name="nonNegativeDecimal">
<xs:restriction base="xs:decimal">
<xs:minInclusive value="0.0"/>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 0b7df4d0bc7c..2890d686186e 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -90,23 +90,35 @@ package com.android.server.display.config {
ctor public HighBrightnessMode();
method @NonNull public final boolean getAllowInLowPowerMode_all();
method public boolean getEnabled();
+ method @Nullable public final java.math.BigDecimal getMinimumHdrPercentOfScreen_all();
method @NonNull public final java.math.BigDecimal getMinimumLux_all();
method @Nullable public final com.android.server.display.config.RefreshRateRange getRefreshRate_all();
+ method @Nullable public final com.android.server.display.config.SdrHdrRatioMap getSdrHdrRatioMap_all();
method @NonNull public final com.android.server.display.config.ThermalStatus getThermalStatusLimit_all();
method public com.android.server.display.config.HbmTiming getTiming_all();
method @NonNull public final java.math.BigDecimal getTransitionPoint_all();
method public final void setAllowInLowPowerMode_all(@NonNull boolean);
method public void setEnabled(boolean);
+ method public final void setMinimumHdrPercentOfScreen_all(@Nullable java.math.BigDecimal);
method public final void setMinimumLux_all(@NonNull java.math.BigDecimal);
method public final void setRefreshRate_all(@Nullable com.android.server.display.config.RefreshRateRange);
+ method public final void setSdrHdrRatioMap_all(@Nullable com.android.server.display.config.SdrHdrRatioMap);
method public final void setThermalStatusLimit_all(@NonNull com.android.server.display.config.ThermalStatus);
method public void setTiming_all(com.android.server.display.config.HbmTiming);
method public final void setTransitionPoint_all(@NonNull java.math.BigDecimal);
}
+ public enum Interpolation {
+ method public String getRawName();
+ enum_constant public static final com.android.server.display.config.Interpolation _default;
+ enum_constant public static final com.android.server.display.config.Interpolation linear;
+ }
+
public class NitsMap {
ctor public NitsMap();
+ method public com.android.server.display.config.Interpolation getInterpolation();
method @NonNull public final java.util.List<com.android.server.display.config.Point> getPoint();
+ method public void setInterpolation(com.android.server.display.config.Interpolation);
}
public class Point {
@@ -125,6 +137,19 @@ package com.android.server.display.config {
method public final void setMinimum(java.math.BigInteger);
}
+ public class SdrHdrRatioMap {
+ ctor public SdrHdrRatioMap();
+ method @NonNull public final java.util.List<com.android.server.display.config.SdrHdrRatioPoint> getPoint();
+ }
+
+ public class SdrHdrRatioPoint {
+ ctor public SdrHdrRatioPoint();
+ method @NonNull public final java.math.BigDecimal getHdrRatio();
+ method @NonNull public final java.math.BigDecimal getSdrNits();
+ method public final void setHdrRatio(@NonNull java.math.BigDecimal);
+ method public final void setSdrNits(@NonNull java.math.BigDecimal);
+ }
+
public class SensorDetails {
ctor public SensorDetails();
method @Nullable public final String getName();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6f41d42b3d54..762d4c1b9a78 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -134,6 +134,7 @@ import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPR
import static android.net.NetworkCapabilities.NET_ENTERPRISE_ID_1;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
+import static android.provider.Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED;
import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
import static android.provider.Telephony.Carriers.DPC_URI;
import static android.provider.Telephony.Carriers.ENFORCE_KEY;
@@ -222,6 +223,7 @@ import android.compat.annotation.EnabledSince;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.IIntentReceiver;
@@ -10951,7 +10953,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (mPendingUserCreatedCallbackTokens.contains(token)) {
// Ignore because it was triggered by createAndManageUser()
Slogf.d(LOG_TAG, "handleNewUserCreated(): ignoring for user " + userId
- + " due to token" + token);
+ + " due to token " + token);
mPendingUserCreatedCallbackTokens.remove(token);
return;
}
@@ -11083,6 +11085,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
switched = mInjector.getIActivityManager().switchUser(userId);
if (!switched) {
Slogf.w(LOG_TAG, "Failed to switch to user %d", userId);
+ } else {
+ Slogf.d(LOG_TAG, "Switched");
}
return switched;
} catch (RemoteException e) {
@@ -11106,18 +11110,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
private @UserIdInt int getLogoutUserIdUnchecked() {
- if (!mInjector.userManagerIsHeadlessSystemUserMode()) {
- // mLogoutUserId is USER_SYSTEM as well, but there's no need to acquire the lock
- return UserHandle.USER_SYSTEM;
- }
synchronized (getLockObject()) {
return mLogoutUserId;
}
}
private void clearLogoutUser() {
- if (!mInjector.userManagerIsHeadlessSystemUserMode()) return; // ignore
-
synchronized (getLockObject()) {
setLogoutUserIdLocked(UserHandle.USER_NULL);
}
@@ -11125,8 +11123,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@GuardedBy("getLockObject()")
private void setLogoutUserIdLocked(@UserIdInt int userId) {
- if (!mInjector.userManagerIsHeadlessSystemUserMode()) return; // ignore
-
if (userId == UserHandle.USER_CURRENT) {
userId = getCurrentForegroundUserId();
}
@@ -11209,8 +11205,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE;
}
- // TODO(b/204585343): remove the headless system user check?
- if (mInjector.userManagerIsHeadlessSystemUserMode() && callingUserId != mInjector
+ if (callingUserId != mInjector
.binderWithCleanCallingIdentity(() -> getCurrentForegroundUserId())) {
Slogf.d(LOG_TAG, "logoutUser(): user %d is in background, just stopping, not switching",
callingUserId);
@@ -11226,8 +11221,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(canManageUsers(caller)
|| hasCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS));
- int result = logoutUserUnchecked(getCurrentForegroundUserId());
- Slogf.d(LOG_TAG, "logout called by uid %d. Result: %d", caller.getUid(), result);
+ int currentUserId = getCurrentForegroundUserId();
+ if (VERBOSE_LOG) {
+ Slogf.v(LOG_TAG, "logout() called by uid %d; current user is %d", caller.getUid(),
+ currentUserId);
+ }
+ int result = logoutUserUnchecked(currentUserId);
+ if (VERBOSE_LOG) {
+ Slogf.v(LOG_TAG, "Result of logout(): %d", result);
+ }
return result;
}
@@ -18669,4 +18671,26 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mContext.sendBroadcastAsUser(intent, user);
}
}
+
+ public boolean isDpcDownloaded() {
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+ ContentResolver cr = mContext.getContentResolver();
+
+ return mInjector.binderWithCleanCallingIdentity(() -> Settings.Secure.getIntForUser(
+ cr, MANAGED_PROVISIONING_DPC_DOWNLOADED,
+ /* def= */ 0, /* userHandle= */ cr.getUserId())
+ == 1);
+ }
+
+ public void setDpcDownloaded(boolean downloaded) {
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS));
+
+ int setTo = downloaded ? 1 : 0;
+
+ mInjector.binderWithCleanCallingIdentity(() -> Settings.Secure.putInt(
+ mContext.getContentResolver(), MANAGED_PROVISIONING_DPC_DOWNLOADED, setTo));
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index f4fae2f81718..c2dec067c870 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1393,7 +1393,6 @@ public final class SystemServer implements Dumpable {
DynamicSystemService dynamicSystem = null;
IStorageManager storageManager = null;
NetworkManagementService networkManagement = null;
- IpSecService ipSecService = null;
VpnManagerService vpnManager = null;
VcnManagementService vcnManagement = null;
NetworkStatsService networkStats = null;
@@ -1898,15 +1897,6 @@ public final class SystemServer implements Dumpable {
}
t.traceEnd();
- t.traceBegin("StartIpSecService");
- try {
- ipSecService = IpSecService.create(context);
- ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
- } catch (Throwable e) {
- reportWtf("starting IpSec Service", e);
- }
- t.traceEnd();
-
t.traceBegin("StartFontManagerService");
mSystemServiceManager.startService(new FontManagerService.Lifecycle(context, safeMode));
t.traceEnd();
@@ -2793,7 +2783,6 @@ public final class SystemServer implements Dumpable {
final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
final MediaRouterService mediaRouterF = mediaRouter;
final MmsServiceBroker mmsServiceF = mmsService;
- final IpSecService ipSecServiceF = ipSecService;
final VpnManagerService vpnManagerF = vpnManager;
final VcnManagementService vcnManagementF = vcnManagement;
final WindowManagerService windowManagerF = wm;
@@ -2885,15 +2874,6 @@ public final class SystemServer implements Dumpable {
.networkScoreAndNetworkManagementServiceReady();
}
t.traceEnd();
- t.traceBegin("MakeIpSecServiceReady");
- try {
- if (ipSecServiceF != null) {
- ipSecServiceF.systemReady();
- }
- } catch (Throwable e) {
- reportWtf("making IpSec Service ready", e);
- }
- t.traceEnd();
t.traceBegin("MakeNetworkStatsServiceReady");
try {
if (networkStatsF != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
index 08de62bc6537..7f571195f5f8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameServiceProviderInstanceImplTest.java
@@ -60,6 +60,7 @@ import android.service.games.IGameServiceController;
import android.service.games.IGameSession;
import android.service.games.IGameSessionController;
import android.service.games.IGameSessionService;
+import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost.SurfacePackage;
import androidx.test.filters.SmallTest;
@@ -746,6 +747,11 @@ public final class GameServiceProviderInstanceImplTest {
mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
mFakeGameService.requestCreateGameSession(10);
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockOverlaySurfacePackage = Mockito.mock(SurfacePackage.class);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockOverlaySurfacePackage));
+
IGameSessionController gameSessionController = getOnlyElement(
mFakeGameSessionService.getCapturedCreateInvocations()).mGameSessionController;
AndroidFuture<GameScreenshotResult> resultFuture = new AndroidFuture<>();
@@ -754,18 +760,28 @@ public final class GameServiceProviderInstanceImplTest {
GameScreenshotResult result = resultFuture.get();
assertEquals(GameScreenshotResult.GAME_SCREENSHOT_ERROR_INTERNAL_ERROR,
result.getStatus());
- verify(mMockWindowManagerService).captureTaskBitmap(10);
+
+ verify(mMockWindowManagerService).captureTaskBitmap(eq(10), any());
}
@Test
public void takeScreenshot_success() throws Exception {
- when(mMockWindowManagerService.captureTaskBitmap(10)).thenReturn(TEST_BITMAP);
+ SurfaceControl mockOverlaySurfaceControl = Mockito.mock(SurfaceControl.class);
+ SurfaceControl[] excludeLayers = new SurfaceControl[1];
+ excludeLayers[0] = mockOverlaySurfaceControl;
+ when(mMockWindowManagerService.captureTaskBitmap(eq(10), any())).thenReturn(TEST_BITMAP);
mGameServiceProviderInstance.start();
startTask(10, GAME_A_MAIN_ACTIVITY);
mockPermissionGranted(Manifest.permission.MANAGE_GAME_ACTIVITY);
mFakeGameService.requestCreateGameSession(10);
+ FakeGameSession gameSession10 = new FakeGameSession();
+ SurfacePackage mockOverlaySurfacePackage = Mockito.mock(SurfacePackage.class);
+ when(mockOverlaySurfacePackage.getSurfaceControl()).thenReturn(mockOverlaySurfaceControl);
+ mFakeGameSessionService.removePendingFutureForTaskId(10)
+ .complete(new CreateGameSessionResult(gameSession10, mockOverlaySurfacePackage));
+
IGameSessionController gameSessionController = getOnlyElement(
mFakeGameSessionService.getCapturedCreateInvocations()).mGameSessionController;
AndroidFuture<GameScreenshotResult> resultFuture = new AndroidFuture<>();
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index bdeb2b4fd839..f9bdad6c62ba 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -204,6 +204,49 @@ public class JobSchedulerServiceTest {
jobInfoBuilder.build(), callingUid, "com.android.test", 0, testTag);
}
+ @Test
+ public void testGetMinJobExecutionGuaranteeMs() {
+ JobStatus ejMax = createJobStatus("testGetMinJobExecutionGuaranteeMs",
+ createJobInfo(1).setExpedited(true));
+ JobStatus ejHigh = createJobStatus("testGetMinJobExecutionGuaranteeMs",
+ createJobInfo(2).setExpedited(true).setPriority(JobInfo.PRIORITY_HIGH));
+ JobStatus ejMaxDowngraded = createJobStatus("testGetMinJobExecutionGuaranteeMs",
+ createJobInfo(3).setExpedited(true));
+ JobStatus ejHighDowngraded = createJobStatus("testGetMinJobExecutionGuaranteeMs",
+ createJobInfo(4).setExpedited(true).setPriority(JobInfo.PRIORITY_HIGH));
+ JobStatus jobHigh = createJobStatus("testGetMinJobExecutionGuaranteeMs",
+ createJobInfo(5).setPriority(JobInfo.PRIORITY_HIGH));
+ JobStatus jobDef = createJobStatus("testGetMinJobExecutionGuaranteeMs",
+ createJobInfo(6));
+
+ spyOn(ejMax);
+ spyOn(ejHigh);
+ spyOn(ejMaxDowngraded);
+ spyOn(ejHighDowngraded);
+ spyOn(jobHigh);
+ spyOn(jobDef);
+
+ when(ejMax.shouldTreatAsExpeditedJob()).thenReturn(true);
+ when(ejHigh.shouldTreatAsExpeditedJob()).thenReturn(true);
+ when(ejMaxDowngraded.shouldTreatAsExpeditedJob()).thenReturn(false);
+ when(ejHighDowngraded.shouldTreatAsExpeditedJob()).thenReturn(false);
+ when(jobHigh.shouldTreatAsExpeditedJob()).thenReturn(false);
+ when(jobDef.shouldTreatAsExpeditedJob()).thenReturn(false);
+
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(ejMax));
+ assertEquals(mService.mConstants.RUNTIME_MIN_EJ_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(ejHigh));
+ assertEquals(mService.mConstants.RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(ejMaxDowngraded));
+ assertEquals(mService.mConstants.RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(ejHighDowngraded));
+ assertEquals(mService.mConstants.RUNTIME_MIN_HIGH_PRIORITY_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobHigh));
+ assertEquals(mService.mConstants.RUNTIME_MIN_GUARANTEE_MS,
+ mService.getMinJobExecutionGuaranteeMs(jobDef));
+ }
+
/**
* Confirm that {@link JobSchedulerService#getRescheduleJobForPeriodic(JobStatus)} returns a job
* with the correct delay and deadline constraints if the periodic job is scheduled with the
diff --git a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
index 9e1445cf589d..dad9fe8648b2 100644
--- a/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
+++ b/services/tests/servicestests/src/com/android/server/audio/AudioDeviceBrokerTest.java
@@ -28,9 +28,10 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
+import android.media.AudioDeviceAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
-import android.media.BtProfileConnectionInfo;
+import android.media.BluetoothProfileConnectionInfo;
import android.util.Log;
import androidx.test.InstrumentationRegistry;
@@ -100,7 +101,7 @@ public class AudioDeviceBrokerTest {
mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
- BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource"));
+ BluetoothProfileConnectionInfo.createA2dpInfo(true, 1), "testSource"));
Thread.sleep(2 * MAX_MESSAGE_HANDLING_DELAY_MS);
verify(mSpyDevInventory, times(1)).setBluetoothActiveDevice(
any(AudioDeviceBroker.BtDeviceInfo.class)
@@ -186,8 +187,9 @@ public class AudioDeviceBrokerTest {
doNothing().when(mSpySystemServer).broadcastStickyIntentToCurrentProfileGroup(
any(Intent.class));
- mSpyDevInventory.setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
- AudioService.CONNECTION_STATE_CONNECTED, address, name, caller);
+ mSpyDevInventory.setWiredDeviceConnectionState(new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_WIRED_HEADSET, address, name),
+ AudioService.CONNECTION_STATE_CONNECTED, caller);
Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
// Verify that the sticky intent is broadcasted
@@ -208,13 +210,13 @@ public class AudioDeviceBrokerTest {
// first connection: ensure the device is connected as a starting condition for the test
mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
- BtProfileConnectionInfo.a2dpInfo(true, 1), "testSource"));
+ BluetoothProfileConnectionInfo.createA2dpInfo(true, 1), "testSource"));
Thread.sleep(MAX_MESSAGE_HANDLING_DELAY_MS);
// disconnection
mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
new AudioDeviceBroker.BtDeviceChangedData(null, mFakeBtDevice,
- BtProfileConnectionInfo.a2dpInfo(false, -1), "testSource"));
+ BluetoothProfileConnectionInfo.createA2dpInfo(false, -1), "testSource"));
if (delayAfterDisconnection > 0) {
Thread.sleep(delayAfterDisconnection);
}
@@ -222,7 +224,7 @@ public class AudioDeviceBrokerTest {
// reconnection
mAudioDeviceBroker.queueOnBluetoothActiveDeviceChanged(
new AudioDeviceBroker.BtDeviceChangedData(mFakeBtDevice, null,
- BtProfileConnectionInfo.a2dpInfo(true, 2), "testSource"));
+ BluetoothProfileConnectionInfo.createA2dpInfo(true, 2), "testSource"));
Thread.sleep(AudioService.BECOMING_NOISY_DELAY_MS + MAX_MESSAGE_HANDLING_DELAY_MS);
// Verify disconnection has been cancelled and we're seeing two connections attempts,
@@ -246,11 +248,11 @@ public class AudioDeviceBrokerTest {
*/
private void checkSingleSystemConnection(BluetoothDevice btDevice) throws Exception {
final String expectedName = btDevice.getName() == null ? "" : btDevice.getName();
+ AudioDeviceAttributes expected = new AudioDeviceAttributes(
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, btDevice.getAddress(), expectedName);
verify(mSpyAudioSystem, times(1)).setDeviceConnectionState(
- ArgumentMatchers.eq(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
+ ArgumentMatchers.argThat(x -> x.equalTypeAddress(expected)),
ArgumentMatchers.eq(AudioSystem.DEVICE_STATE_AVAILABLE),
- ArgumentMatchers.eq(btDevice.getAddress()),
- ArgumentMatchers.eq(expectedName),
anyInt() /*codec*/);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
index 8d706cb960e9..1f355b096335 100644
--- a/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
+++ b/services/tests/servicestests/src/com/android/server/audio/NoOpAudioSystemAdapter.java
@@ -48,11 +48,10 @@ public class NoOpAudioSystemAdapter extends AudioSystemAdapter {
//-----------------------------------------------------------------
// Overrides of AudioSystemAdapter
@Override
- public int setDeviceConnectionState(int device, int state, String deviceAddress,
- String deviceName, int codecFormat) {
- Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, %s, %s, 0x%s",
- Integer.toHexString(device), state, deviceAddress, deviceName,
- Integer.toHexString(codecFormat)));
+ public int setDeviceConnectionState(AudioDeviceAttributes attributes, int state,
+ int codecFormat) {
+ Log.i(TAG, String.format("setDeviceConnectionState(0x%s, %d, 0x%s",
+ attributes.toString(), state, Integer.toHexString(codecFormat)));
return AudioSystem.AUDIO_STATUS_OK;
}
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index 24a47516a366..f352de4ea54e 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -36,8 +36,11 @@ import android.util.Spline;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.display.whitebalance.DisplayWhiteBalanceController;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import java.util.Arrays;
@@ -147,11 +150,14 @@ public class BrightnessMappingStrategyTest {
private static final float TOLERANCE = 0.0001f;
+ @Mock
+ DisplayWhiteBalanceController mMockDwbc;
+
@Test
public void testSimpleStrategyMappingAtControlPoints() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, 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,
@@ -166,7 +172,7 @@ public class BrightnessMappingStrategyTest {
public void testSimpleStrategyMappingBetweenControlPoints() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy simple = BrightnessMappingStrategy.create(res, ddc, 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;
@@ -181,7 +187,7 @@ public class BrightnessMappingStrategyTest {
public void testSimpleStrategyIgnoresNewConfiguration() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
final float[] lux = { 0f, 1f };
final float[] nits = { 0, PowerManager.BRIGHTNESS_ON };
@@ -196,7 +202,7 @@ public class BrightnessMappingStrategyTest {
public void testSimpleStrategyIgnoresNullConfiguration() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
strategy.setBrightnessConfiguration(null);
final int N = DISPLAY_LEVELS_BACKLIGHT.length;
@@ -210,7 +216,7 @@ public class BrightnessMappingStrategyTest {
public void testPhysicalStrategyMappingAtControlPoints() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc, 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],
@@ -227,7 +233,7 @@ public class BrightnessMappingStrategyTest {
public void testPhysicalStrategyMappingBetweenControlPoints() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertNotNull("BrightnessMappingStrategy should not be null", physical);
Spline brightnessToNits =
Spline.createSpline(BACKLIGHT_RANGE_ZERO_TO_ONE, DISPLAY_RANGE_NITS);
@@ -244,7 +250,7 @@ public class BrightnessMappingStrategyTest {
public void testPhysicalStrategyUsesNewConfigurations() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
final float[] lux = { 0f, 1f };
final float[] nits = {
@@ -269,7 +275,7 @@ public class BrightnessMappingStrategyTest {
public void testPhysicalStrategyRecalculateSplines() {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS);
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, 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;
@@ -301,7 +307,7 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT,
DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertTrue(strategy instanceof BrightnessMappingStrategy.PhysicalMappingStrategy);
}
@@ -314,13 +320,13 @@ public class BrightnessMappingStrategyTest {
lux[idx+1] = tmp;
Resources res = createResources(lux, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertNull(strategy);
// And make sure we get the same result even if it's monotone but not increasing.
lux[idx] = lux[idx+1];
res = createResources(lux, DISPLAY_LEVELS_NITS);
- strategy = BrightnessMappingStrategy.create(res, ddc);
+ strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertNull(strategy);
}
@@ -333,11 +339,11 @@ public class BrightnessMappingStrategyTest {
lux[lux.length - 1] = lux[lux.length - 2] + 1;
Resources res = createResources(lux, DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertNull(strategy);
res = createResources(lux, DISPLAY_LEVELS_BACKLIGHT);
- strategy = BrightnessMappingStrategy.create(res, ddc);
+ strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertNull(strategy);
// Extra backlight level
@@ -345,14 +351,14 @@ public class BrightnessMappingStrategyTest {
DISPLAY_LEVELS_BACKLIGHT, DISPLAY_LEVELS_BACKLIGHT.length+1);
backlight[backlight.length - 1] = backlight[backlight.length - 2] + 1;
res = createResources(LUX_LEVELS, backlight);
- strategy = BrightnessMappingStrategy.create(res, ddc);
+ strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertNull(strategy);
// Extra nits level
final float[] nits = Arrays.copyOf(DISPLAY_RANGE_NITS, DISPLAY_LEVELS_NITS.length+1);
nits[nits.length - 1] = nits[nits.length - 2] + 1;
res = createResources(LUX_LEVELS, nits);
- strategy = BrightnessMappingStrategy.create(res, ddc);
+ strategy = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertNull(strategy);
}
@@ -361,17 +367,17 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc(EMPTY_FLOAT_ARRAY /*nitsRange*/);
- BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc);
+ BrightnessMappingStrategy physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertNull(physical);
res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
DISPLAY_LEVELS_NITS);
- physical = BrightnessMappingStrategy.create(res, ddc);
+ physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertNull(physical);
res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
DISPLAY_LEVELS_NITS);
- physical = BrightnessMappingStrategy.create(res, ddc);
+ physical = BrightnessMappingStrategy.create(res, ddc, mMockDwbc);
assertNull(physical);
}
@@ -380,10 +386,10 @@ public class BrightnessMappingStrategyTest {
Resources res = createResources(LUX_LEVELS, EMPTY_INT_ARRAY /*brightnessLevelsBacklight*/,
DISPLAY_LEVELS_NITS);
DisplayDeviceConfig ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
- assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc));
+ assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc, mMockDwbc));
ddc = createDdc(DISPLAY_RANGE_NITS, BACKLIGHT_RANGE_ZERO_TO_ONE);
res = createResources(LUX_LEVELS, DISPLAY_LEVELS_BACKLIGHT);
- assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc));
+ assertStrategyAdaptsToUserDataPoints(BrightnessMappingStrategy.create(res, ddc, mMockDwbc));
}
@Test
@@ -394,7 +400,7 @@ 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,
- null);
+ mMockDwbc);
assertNotNull("BrightnessMappingStrategy should not be null", bms);
// Ensure that the config is the one we set
@@ -586,7 +592,8 @@ public class BrightnessMappingStrategyTest {
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
+ mMockDwbc);
// Let's start with a validity check:
assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
@@ -614,7 +621,8 @@ public class BrightnessMappingStrategyTest {
final float y3 = GAMMA_CORRECTION_SPLINE.interpolate(x3);
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
+ mMockDwbc);
// Validity check:
assertEquals(y1, strategy.getBrightness(x1), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
@@ -639,7 +647,8 @@ public class BrightnessMappingStrategyTest {
// just make sure the adjustment reflects the change.
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
+ mMockDwbc);
assertEquals(0.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
strategy.addUserDataPoint(2500, 1.0f);
assertEquals(+1.0f, strategy.getAutoBrightnessAdjustment(), 0.0001f /* tolerance */);
@@ -660,7 +669,8 @@ public class BrightnessMappingStrategyTest {
final float y4 = GAMMA_CORRECTION_SPLINE.interpolate(x4);
Resources resources = createResources(GAMMA_CORRECTION_LUX, GAMMA_CORRECTION_NITS);
DisplayDeviceConfig ddc = createDdc();
- BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc);
+ BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(resources, ddc,
+ mMockDwbc);
// Validity, as per tradition:
assertEquals(y0, strategy.getBrightness(x0), 0.0001f /* tolerance */);
assertEquals(y2, strategy.getBrightness(x2), 0.0001f /* tolerance */);
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index 6203c2f54f07..53fa3e2db376 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -22,11 +22,14 @@ import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR;
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
import static android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT;
+
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
import static com.android.server.display.AutomaticBrightnessController
.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE;
+import static com.android.server.display.DisplayDeviceConfig.HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT;
+
import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;
import static org.junit.Assert.assertEquals;
@@ -111,7 +114,8 @@ public class HighBrightnessModeControllerTest {
private static final HighBrightnessModeData DEFAULT_HBM_DATA =
new HighBrightnessModeData(MINIMUM_LUX, TRANSITION_POINT, TIME_WINDOW_MILLIS,
TIME_ALLOWED_IN_WINDOW_MILLIS, TIME_MINIMUM_AVAILABLE_TO_ENABLE_MILLIS,
- THERMAL_STATUS_LIMIT, ALLOW_IN_LOW_POWER_MODE);
+ THERMAL_STATUS_LIMIT, ALLOW_IN_LOW_POWER_MODE,
+ HDR_PERCENT_OF_SCREEN_REQUIRED_DEFAULT);
@Before
public void setUp() {
@@ -136,7 +140,7 @@ public class HighBrightnessModeControllerTest {
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
- mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, () -> {}, mContextSpy);
+ mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy);
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
assertEquals(hbmc.getTransitionPoint(), HBM_TRANSITION_POINT_INVALID, 0.0f);
}
@@ -146,7 +150,7 @@ public class HighBrightnessModeControllerTest {
initHandler(null);
final HighBrightnessModeController hbmc = new HighBrightnessModeController(
mInjectorMock, mHandler, DISPLAY_WIDTH, DISPLAY_HEIGHT, mDisplayToken,
- mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, () -> {}, mContextSpy);
+ mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX, null, null, () -> {}, mContextSpy);
hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
hbmc.onAmbientLuxChange(MINIMUM_LUX - 1); // below allowed range
assertState(hbmc, DEFAULT_MIN, DEFAULT_MAX, HIGH_BRIGHTNESS_MODE_OFF);
@@ -703,7 +707,7 @@ public class HighBrightnessModeControllerTest {
initHandler(clock);
return new HighBrightnessModeController(mInjectorMock, mHandler, DISPLAY_WIDTH,
DISPLAY_HEIGHT, mDisplayToken, mDisplayUniqueId, DEFAULT_MIN, DEFAULT_MAX,
- DEFAULT_HBM_DATA, () -> {}, mContextSpy);
+ DEFAULT_HBM_DATA, null, () -> {}, mContextSpy);
}
private void initHandler(OffsettableClock clock) {
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index b6c4bc23f0e4..a9812ab9bb03 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -62,6 +62,23 @@ import java.util.concurrent.TimeUnit;
public class HdmiCecLocalDeviceTvTest {
private static final int TIMEOUT_MS = HdmiConfig.TIMEOUT_MS + 1;
+ private static final String[] SADS_NOT_TO_QUERY = new String[]{
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MPEG1,
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_AAC,
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTS,
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ATRAC,
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_ONEBITAUDIO,
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DDP,
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DTSHD,
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD,
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST,
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
+ HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX};
+ private static final HdmiCecMessage SAD_QUERY =
+ HdmiCecMessageBuilder.buildRequestShortAudioDescriptor(ADDR_TV, ADDR_AUDIO_SYSTEM,
+ new int[]{Constants.AUDIO_CODEC_LPCM, Constants.AUDIO_CODEC_DD,
+ Constants.AUDIO_CODEC_MP3, Constants.AUDIO_CODEC_MPEG2});
+
private HdmiControlService mHdmiControlService;
private HdmiCecController mHdmiCecController;
private HdmiCecLocalDeviceTv mHdmiCecLocalDeviceTv;
@@ -136,6 +153,10 @@ public class HdmiCecLocalDeviceTvTest {
mNativeWrapper.setPhysicalAddress(mTvPhysicalAddress);
mTestLooper.dispatchAll();
mTvLogicalAddress = mHdmiCecLocalDeviceTv.getDeviceInfo().getLogicalAddress();
+ for (String sad : SADS_NOT_TO_QUERY) {
+ mHdmiControlService.getHdmiCecConfig().setIntValue(
+ sad, HdmiControlManager.QUERY_SAD_DISABLED);
+ }
mNativeWrapper.clearResultMessages();
}
@@ -442,6 +463,7 @@ public class HdmiCecLocalDeviceTvTest {
ADDR_TV,
ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SAD_QUERY);
}
@Test
@@ -463,6 +485,7 @@ public class HdmiCecLocalDeviceTvTest {
ADDR_TV,
ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).doesNotContain(reportArcInitiated);
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(SAD_QUERY);
}
@Test
@@ -485,6 +508,7 @@ public class HdmiCecLocalDeviceTvTest {
ADDR_TV,
ADDR_AUDIO_SYSTEM);
assertThat(mNativeWrapper.getResultMessages()).contains(reportArcInitiated);
+ assertThat(mNativeWrapper.getResultMessages()).contains(SAD_QUERY);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 687779d686d1..fb3a6264169a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.window.BackNavigationInfo.typeToString;
import static com.google.common.truth.Truth.assertThat;
@@ -71,7 +72,8 @@ public class BackNavigationControllerTests extends WindowTestsBase {
@Test
public void backTypeCrossActivityWhenBackToPreviousActivity() {
Task task = createTopTaskWithActivity();
- mAtm.setFocusedTask(task.mTaskId, createActivityRecord(task));
+ mAtm.setFocusedTask(task.mTaskId,
+ createAppWindow(task, FIRST_APPLICATION_WINDOW, "window").mActivityRecord);
BackNavigationInfo backNavigationInfo =
mBackNavigationController.startBackNavigation(task, new StubTransaction());
assertThat(backNavigationInfo).isNotNull();
@@ -85,7 +87,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
@Test
public void backNavInfoFullyPopulated() {
Task task = createTopTaskWithActivity();
- createActivityRecord(task);
+ createAppWindow(task, FIRST_APPLICATION_WINDOW, "window");
// We need a mock screenshot so
TaskSnapshotController taskSnapshotController = createMockTaskSnapshotController();
@@ -115,6 +117,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
private Task createTopTaskWithActivity() {
Task task = createTask(mDefaultDisplay);
ActivityRecord record = createActivityRecord(task);
+ createWindow(null, FIRST_APPLICATION_WINDOW, record, "window");
when(record.mSurfaceControl.isValid()).thenReturn(true);
mAtm.setFocusedTask(task.mTaskId, record);
return task;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 65b5cf5f13c4..dcaa511bf7cc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -80,7 +80,6 @@ import android.app.IApplicationThread;
import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
-import android.graphics.Rect;
import android.os.Binder;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
@@ -231,34 +230,6 @@ public class RootTaskTests extends WindowTestsBase {
}
@Test
- public void testTaskOutset() {
- final Task task = createTask(mDisplayContent);
- final int taskOutset = 10;
- spyOn(task);
- doReturn(taskOutset).when(task).getTaskOutset();
- doReturn(true).when(task).inMultiWindowMode();
-
- // Mock the resolved override windowing mode to non-fullscreen
- final WindowConfiguration windowConfiguration =
- task.getResolvedOverrideConfiguration().windowConfiguration;
- spyOn(windowConfiguration);
- doReturn(WINDOWING_MODE_MULTI_WINDOW)
- .when(windowConfiguration).getWindowingMode();
-
- // Prevent adjust task dimensions
- doNothing().when(task).adjustForMinimalTaskDimensions(any(), any(), any());
-
- final Rect taskBounds = new Rect(200, 200, 800, 1000);
- // Update surface position and size by the given bounds.
- task.setBounds(taskBounds);
-
- assertEquals(taskBounds.width() + 2 * taskOutset, task.getLastSurfaceSize().x);
- assertEquals(taskBounds.height() + 2 * taskOutset, task.getLastSurfaceSize().y);
- assertEquals(taskBounds.left - taskOutset, task.getLastSurfacePosition().x);
- assertEquals(taskBounds.top - taskOutset, task.getLastSurfacePosition().y);
- }
-
- @Test
public void testActivityAndTaskGetsProperType() {
final Task task1 = new TaskBuilder(mSupervisor).build();
ActivityRecord activity1 = createNonAttachedActivityRecord(mDisplayContent);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 98a41bcf5adf..4a761a7a47be 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1814,6 +1814,7 @@ public class UsageStatsService extends SystemService implements
synchronized (mLock) {
mResponseStatsTracker.dump(idpw);
}
+ return;
} else if (arg != null && !arg.startsWith("-")) {
// Anything else that doesn't start with '-' is a pkg to filter
pkgs.add(arg);
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
index 85b1de5478e1..337e1f92050c 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaDevice.java
@@ -17,6 +17,7 @@
package com.android.server.usb;
import android.annotation.NonNull;
+import android.media.AudioDeviceAttributes;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.os.RemoteException;
@@ -213,24 +214,25 @@ public final class UsbAlsaDevice {
int outputState = (enable && connected) ? 1 : 0;
if (outputState != mOutputState) {
mOutputState = outputState;
- mAudioService.setWiredDeviceConnectionState(device, outputState,
- alsaCardDeviceString,
- mDeviceName, TAG);
+ AudioDeviceAttributes attributes = new AudioDeviceAttributes(device,
+ alsaCardDeviceString, mDeviceName);
+ mAudioService.setWiredDeviceConnectionState(attributes, outputState, TAG);
}
}
// Input Device
if (mHasInput) {
- int device = mIsInputHeadset ? AudioSystem.DEVICE_IN_USB_HEADSET
+ int device = mIsInputHeadset
+ ? AudioSystem.DEVICE_IN_USB_HEADSET
: AudioSystem.DEVICE_IN_USB_DEVICE;
boolean connected = isInputJackConnected();
Slog.i(TAG, "INPUT JACK connected: " + connected);
int inputState = (enable && connected) ? 1 : 0;
if (inputState != mInputState) {
mInputState = inputState;
- mAudioService.setWiredDeviceConnectionState(
- device, inputState, alsaCardDeviceString,
- mDeviceName, TAG);
+ AudioDeviceAttributes attributes = new AudioDeviceAttributes(device,
+ alsaCardDeviceString, mDeviceName);
+ mAudioService.setWiredDeviceConnectionState(attributes, inputState, TAG);
}
}
} catch (RemoteException e) {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index e560f34cfcd8..d7cdb507362a 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -356,13 +356,17 @@ public class TelecomManager {
"android.telecom.extra.INCOMING_CALL_EXTRAS";
/**
- * Optional extra for {@link #ACTION_INCOMING_CALL} containing a boolean to indicate that the
- * call has an externally generated ringer. Used by the HfpClientConnectionService when In Band
- * Ringtone is enabled to prevent two ringers from being generated.
+ * Optional extra for {@link #addNewIncomingCall(PhoneAccountHandle, Bundle)} used to indicate
+ * that a call has an in-band ringtone associated with it. This is used when the device is
+ * acting as an HFP headset and the Bluetooth stack has received an in-band ringtone from the
+ * the HFP host which must be played instead of any local ringtone the device would otherwise
+ * have generated.
+ *
* @hide
*/
- public static final String EXTRA_CALL_EXTERNAL_RINGER =
- "android.telecom.extra.CALL_EXTERNAL_RINGER";
+ @SystemApi
+ public static final String EXTRA_CALL_HAS_IN_BAND_RINGTONE =
+ "android.telecom.extra.CALL_HAS_IN_BAND_RINGTONE";
/**
* Optional extra for {@link android.content.Intent#ACTION_CALL} and
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index e88106cb95fe..86b98f1cbe79 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -127,7 +127,9 @@ public class Annotation {
ApnSetting.TYPE_EMERGENCY,
ApnSetting.TYPE_MCX,
ApnSetting.TYPE_XCAP,
- // ApnSetting.TYPE_ENTERPRISE
+ ApnSetting.TYPE_BIP,
+ ApnSetting.TYPE_VSIM,
+ ApnSetting.TYPE_ENTERPRISE
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApnType {
@@ -707,6 +709,9 @@ public class Annotation {
NetworkCapabilities.NET_CAPABILITY_VSIM,
NetworkCapabilities.NET_CAPABILITY_BIP,
NetworkCapabilities.NET_CAPABILITY_HEAD_UNIT,
+ NetworkCapabilities.NET_CAPABILITY_MMTEL,
+ NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY,
+ NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_BANDWIDTH
})
public @interface NetCapability { }
@@ -721,4 +726,16 @@ public class Annotation {
NetworkAgent.VALIDATION_STATUS_NOT_VALID
})
public @interface ValidationStatus {}
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "NET_CAPABILITY_ENTERPRISE_SUB_LEVEL" }, value = {
+ NetworkCapabilities.NET_ENTERPRISE_ID_1,
+ NetworkCapabilities.NET_ENTERPRISE_ID_2,
+ NetworkCapabilities.NET_ENTERPRISE_ID_3,
+ NetworkCapabilities.NET_ENTERPRISE_ID_4,
+ NetworkCapabilities.NET_ENTERPRISE_ID_5
+ })
+
+ public @interface EnterpriseId {}
}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index 5a12865fb2a0..e0145e661660 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -79,7 +79,7 @@ public class SmsMessage {
public static final int ENCODING_8BIT = 2;
public static final int ENCODING_16BIT = 3;
/**
- * @hide This value is not defined in global standard. Only in Korea, this is used.
+ * This value is not defined in global standard. Only in Korea, this is used.
*/
public static final int ENCODING_KSC5601 = 4;
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index a166a5d6404c..fa1bae41f433 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -26,10 +26,10 @@ import android.annotation.SystemApi;
import android.net.NetworkCapabilities;
import android.os.Parcel;
import android.os.Parcelable;
-import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.NetCapability;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager.NetworkTypeBitMask;
+import android.telephony.data.ApnSetting.ApnType;
import android.telephony.data.ApnSetting.AuthType;
import android.text.TextUtils;
@@ -245,8 +245,7 @@ public final class DataProfile implements Parcelable {
* @return The supported APN types bitmask.
* @deprecated Use {@link #getApnSetting()} and {@link ApnSetting#getApnTypeBitmask()} instead.
*/
- @Deprecated
- public @ApnType int getSupportedApnTypesBitmask() {
+ @Deprecated public @ApnType int getSupportedApnTypesBitmask() {
if (mApnSetting != null) {
return mApnSetting.getApnTypeBitmask();
}
@@ -425,6 +424,12 @@ public final class DataProfile implements Parcelable {
return ApnSetting.TYPE_MCX;
case NetworkCapabilities.NET_CAPABILITY_IA:
return ApnSetting.TYPE_IA;
+ case NetworkCapabilities.NET_CAPABILITY_BIP:
+ return ApnSetting.TYPE_BIP;
+ case NetworkCapabilities.NET_CAPABILITY_VSIM:
+ return ApnSetting.TYPE_VSIM;
+ case NetworkCapabilities.NET_CAPABILITY_ENTERPRISE:
+ return ApnSetting.TYPE_ENTERPRISE;
default:
return ApnSetting.TYPE_NONE;
}
diff --git a/telephony/java/android/telephony/data/DataServiceCallback.java b/telephony/java/android/telephony/data/DataServiceCallback.java
index 1ff6ec1779cd..ec734716f6e4 100644
--- a/telephony/java/android/telephony/data/DataServiceCallback.java
+++ b/telephony/java/android/telephony/data/DataServiceCallback.java
@@ -261,9 +261,10 @@ public class DataServiceCallback {
}
/**
- * Unthrottles the APN on the current transport. There is no matching "APN throttle" method.
- * Instead, the APN is throttled when {@link IDataService#setupDataCall} fails within
- * the time specified by {@link DataCallResponse#getRetryDurationMillis}.
+ * Unthrottles the APN on the current transport.
+ * The APN is throttled when {@link IDataService#setupDataCall} fails within
+ * the time specified by {@link DataCallResponse#getRetryDurationMillis} and will remain
+ * throttled until this method is called.
* <p/>
* see: {@link DataCallResponse#getRetryDurationMillis}
*
@@ -284,9 +285,9 @@ public class DataServiceCallback {
/**
* Unthrottles the DataProfile on the current transport.
- * There is no matching "DataProfile throttle" method.
- * Instead, the DataProfile is throttled when {@link IDataService#setupDataCall} fails within
- * the time specified by {@link DataCallResponse#getRetryDurationMillis}.
+ * The DataProfile is throttled when {@link IDataService#setupDataCall} fails within
+ * the time specified by {@link DataCallResponse#getRetryDurationMillis} and will remain
+ * throttled until this method is called.
* <p/>
* see: {@link DataCallResponse#getRetryDurationMillis}
*
diff --git a/telephony/java/android/telephony/data/TrafficDescriptor.java b/telephony/java/android/telephony/data/TrafficDescriptor.java
index 2178fc1717b9..66dcf8f49e9c 100644
--- a/telephony/java/android/telephony/data/TrafficDescriptor.java
+++ b/telephony/java/android/telephony/data/TrafficDescriptor.java
@@ -21,8 +21,13 @@ import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
-import java.util.Arrays;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* A traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2. It is used for UE Route Selection
@@ -31,24 +36,215 @@ import java.util.Objects;
* not specify the end point to be used for the data call.
*/
public final class TrafficDescriptor implements Parcelable {
+ /**
+ * The OS/App id
+ *
+ * @hide
+ */
+ public static final class OsAppId {
+ /**
+ * OSId for "Android", using UUID version 5 with namespace ISO OSI.
+ * Prepended to the OsAppId in TrafficDescriptor to use for URSP matching.
+ */
+ public static final UUID ANDROID_OS_ID =
+ UUID.fromString("97a498e3-fc92-5c94-8986-0333d06e4e47");
+
+ /**
+ * Allowed app ids.
+ */
+ // The following app ids are the only apps id Android supports. OEMs or vendors are
+ // prohibited to modify/extend the allowed list, especially passing the real package name to
+ // the network.
+ private static final Set<String> ALLOWED_APP_IDS = Set.of(
+ "ENTERPRISE", "PRIORITIZE_LATENCY", "PRIORITIZE_BANDWIDTH", "CBS"
+ );
+
+ /** OS id in UUID format. */
+ private final @NonNull UUID mOsId;
+
+ /**
+ * App id in string format. Note that Android will not allow use specific app id. This must
+ * be a category/capability identifier.
+ */
+ private final @NonNull String mAppId;
+
+ /**
+ * The differentiator when multiple traffic descriptor has the same OS and app id. Must be
+ * greater than 1.
+ */
+ private final int mDifferentiator;
+
+ /**
+ * Constructor
+ *
+ * @param osId OS id in UUID format.
+ * @param appId App id in string format. Note that Android will not allow use specific app
+ * id. This must be a category/capability identifier.
+ */
+ public OsAppId(@NonNull UUID osId, @NonNull String appId) {
+ this(osId, appId, 1);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param osId OS id in UUID format.
+ * @param appId App id in string format. Note that Android will not allow use specific app
+ * id. This must be a category/capability identifier.
+ * @param differentiator The differentiator when multiple traffic descriptor has the same
+ * OS and app id. Must be greater than 0.
+ */
+ public OsAppId(@NonNull UUID osId, @NonNull String appId, int differentiator) {
+ Objects.requireNonNull(osId);
+ Objects.requireNonNull(appId);
+ if (differentiator < 1) {
+ throw new IllegalArgumentException("Invalid differentiator " + differentiator);
+ }
+
+ mOsId = osId;
+ mAppId = appId;
+ mDifferentiator = differentiator;
+ }
+
+ /**
+ * Constructor from raw byte array.
+ *
+ * @param rawOsAppId The raw OS/App id.
+ */
+ public OsAppId(@NonNull byte[] rawOsAppId) {
+ try {
+ ByteBuffer bb = ByteBuffer.wrap(rawOsAppId);
+ // OS id is the first 16 bytes.
+ mOsId = new UUID(bb.getLong(), bb.getLong());
+ // App id length is 1 byte.
+ int appIdLen = bb.get();
+ // The remaining is the app id + differentiator.
+ byte[] appIdAndDifferentiator = new byte[appIdLen];
+ bb.get(appIdAndDifferentiator, 0, appIdLen);
+ // Extract trailing numbers, for example, "ENTERPRISE", "ENTERPRISE3".
+ String appIdAndDifferentiatorStr = new String(appIdAndDifferentiator);
+ Pattern pattern = Pattern.compile("[^0-9]+([0-9]+)$");
+ Matcher matcher = pattern.matcher(new String(appIdAndDifferentiator));
+ if (matcher.find()) {
+ mDifferentiator = Integer.parseInt(matcher.group(1));
+ mAppId = appIdAndDifferentiatorStr.replace(matcher.group(1), "");
+ } else {
+ mDifferentiator = 1;
+ mAppId = appIdAndDifferentiatorStr;
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to decode " + (rawOsAppId != null
+ ? new BigInteger(1, rawOsAppId).toString(16) : null));
+ }
+ }
+
+ /**
+ * @return The OS id in UUID format.
+ */
+ public @NonNull UUID getOsId() {
+ return mOsId;
+ }
+
+ /**
+ * @return App id in string format. Note that Android will not allow use specific app id.
+ * This must be a category/capability identifier.
+ */
+ public @NonNull String getAppId() {
+ return mAppId;
+ }
+
+ /**
+ * @return The differentiator when multiple traffic descriptor has the same OS and app id.
+ * Must be greater than 1.
+ */
+ public int getDifferentiator() {
+ return mDifferentiator;
+ }
+
+ /**
+ * @return OS/App id in raw byte format.
+ */
+ public @NonNull byte[] getBytes() {
+ byte[] osAppId = (mAppId + (mDifferentiator > 1 ? mDifferentiator : "")).getBytes();
+ // 16 bytes for UUID, 1 byte for length of osAppId, and up to 255 bytes for osAppId
+ ByteBuffer bb = ByteBuffer.allocate(16 + 1 + osAppId.length);
+ bb.putLong(mOsId.getMostSignificantBits());
+ bb.putLong(mOsId.getLeastSignificantBits());
+ bb.put((byte) osAppId.length);
+ bb.put(osAppId);
+ return bb.array();
+ }
+
+ @Override
+ public String toString() {
+ return "[OsAppId: OS=" + mOsId + ", App=" + mAppId + ", differentiator="
+ + mDifferentiator + ", raw="
+ + new BigInteger(1, getBytes()).toString(16) + "]";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ OsAppId osAppId = (OsAppId) o;
+ return mDifferentiator == osAppId.mDifferentiator && mOsId.equals(osAppId.mOsId)
+ && mAppId.equals(osAppId.mAppId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mOsId, mAppId, mDifferentiator);
+ }
+ }
+
private final String mDnn;
- private final byte[] mOsAppId;
+ private final OsAppId mOsAppId;
private TrafficDescriptor(@NonNull Parcel in) {
mDnn = in.readString();
- mOsAppId = in.createByteArray();
+ byte[] osAppIdBytes = in.createByteArray();
+ OsAppId osAppId = null;
+ if (osAppIdBytes != null) {
+ osAppId = new OsAppId(osAppIdBytes);
+ }
+ mOsAppId = osAppId;
+
+ enforceAllowedIds();
}
/**
* Create a traffic descriptor, as defined in 3GPP TS 24.526 Section 5.2
* @param dnn optional DNN, which must be used for traffic matching, if present
- * @param osAppId OsId + osAppId of the traffic descriptor
+ * @param osAppIdRawBytes Raw bytes of OsId + osAppId of the traffic descriptor
*
* @hide
*/
- public TrafficDescriptor(String dnn, byte[] osAppId) {
+ public TrafficDescriptor(String dnn, @Nullable byte[] osAppIdRawBytes) {
mDnn = dnn;
+ OsAppId osAppId = null;
+ if (osAppIdRawBytes != null) {
+ osAppId = new OsAppId(osAppIdRawBytes);
+ }
mOsAppId = osAppId;
+
+ enforceAllowedIds();
+ }
+
+ /**
+ * Enforce the OS id and app id are in the allowed list.
+ *
+ * @throws IllegalArgumentException if ids are not allowed.
+ */
+ private void enforceAllowedIds() {
+ if (mOsAppId != null && !mOsAppId.getOsId().equals(OsAppId.ANDROID_OS_ID)) {
+ throw new IllegalArgumentException("OS id " + mOsAppId.getOsId() + " does not match "
+ + OsAppId.ANDROID_OS_ID);
+ }
+
+ if (mOsAppId != null && !OsAppId.ALLOWED_APP_IDS.contains(mOsAppId.getAppId())) {
+ throw new IllegalArgumentException("Illegal app id " + mOsAppId.getAppId()
+ + ". Only allowing one of the following " + OsAppId.ALLOWED_APP_IDS);
+ }
}
/**
@@ -61,13 +257,13 @@ public final class TrafficDescriptor implements Parcelable {
}
/**
- * OsAppId is the app id as defined in 3GPP TS 24.526 Section 5.2, and it identifies a traffic
- * category. It includes the OS Id component of the field as defined in the specs.
- * @return the OS App ID of this traffic descriptor if one is included by the network, null
- * otherwise.
+ * OsAppId identifies a broader traffic category. Although it names Os/App id, it only includes
+ * OS version with a general/broader category id used as app id.
+ *
+ * @return The id in byte format. {@code null} if not available.
*/
public @Nullable byte[] getOsAppId() {
- return mOsAppId;
+ return mOsAppId != null ? mOsAppId.getBytes() : null;
}
@Override
@@ -77,13 +273,13 @@ public final class TrafficDescriptor implements Parcelable {
@NonNull @Override
public String toString() {
- return "TrafficDescriptor={mDnn=" + mDnn + ", mOsAppId=" + mOsAppId + "}";
+ return "TrafficDescriptor={mDnn=" + mDnn + ", " + mOsAppId + "}";
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeString(mDnn);
- dest.writeByteArray(mOsAppId);
+ dest.writeByteArray(mOsAppId != null ? mOsAppId.getBytes() : null);
}
public static final @NonNull Parcelable.Creator<TrafficDescriptor> CREATOR =
@@ -104,7 +300,7 @@ public final class TrafficDescriptor implements Parcelable {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TrafficDescriptor that = (TrafficDescriptor) o;
- return Objects.equals(mDnn, that.mDnn) && Arrays.equals(mOsAppId, that.mOsAppId);
+ return Objects.equals(mDnn, that.mDnn) && Objects.equals(mOsAppId, that.mOsAppId);
}
@Override
@@ -148,7 +344,7 @@ public final class TrafficDescriptor implements Parcelable {
}
/**
- * Set the OS App ID (including OS Id as defind in the specs).
+ * Set the OS App ID (including OS Id as defined in the specs).
*
* @return The same instance of the builder.
*/
diff --git a/telephony/java/android/telephony/ims/RcsClientConfiguration.java b/telephony/java/android/telephony/ims/RcsClientConfiguration.java
index c25ace0c6a62..f367e404a35b 100644
--- a/telephony/java/android/telephony/ims/RcsClientConfiguration.java
+++ b/telephony/java/android/telephony/ims/RcsClientConfiguration.java
@@ -34,7 +34,7 @@ public final class RcsClientConfiguration implements Parcelable {
/**@hide*/
@StringDef(prefix = "RCS_PROFILE_",
- value = {RCS_PROFILE_1_0, RCS_PROFILE_2_3})
+ value = {RCS_PROFILE_1_0, RCS_PROFILE_2_3, RCS_PROFILE_2_4})
public @interface StringRcsProfile {}
/**
@@ -45,6 +45,10 @@ public final class RcsClientConfiguration implements Parcelable {
* RCS profile UP 2.3
*/
public static final String RCS_PROFILE_2_3 = "UP_2.3";
+ /**
+ * RCS profile UP 2.4
+ */
+ public static final String RCS_PROFILE_2_4 = "UP_2.4";
private String mRcsVersion;
private String mRcsProfile;
@@ -58,8 +62,8 @@ public final class RcsClientConfiguration implements Parcelable {
* @param rcsVersion The parameter identifies the RCS version supported
* by the client. Refer to GSMA RCC.07 "rcs_version" parameter.
* @param rcsProfile Identifies a fixed set of RCS services that are
- * supported by the client. See {@link #RCS_PROFILE_1_0 } or
- * {@link #RCS_PROFILE_2_3 }
+ * supported by the client. See {@link #RCS_PROFILE_1_0 },
+ * {@link #RCS_PROFILE_2_3 } or {@link #RCS_PROFILE_2_4 }
* @param clientVendor Identifies the vendor providing the RCS client.
* @param clientVersion Identifies the RCS client version. Refer to GSMA
* RCC.07 "client_version" parameter.
@@ -80,8 +84,8 @@ public final class RcsClientConfiguration implements Parcelable {
* @param rcsVersion The parameter identifies the RCS version supported
* by the client. Refer to GSMA RCC.07 "rcs_version" parameter.
* @param rcsProfile Identifies a fixed set of RCS services that are
- * supported by the client. See {@link #RCS_PROFILE_1_0 } or
- * {@link #RCS_PROFILE_2_3 }
+ * supported by the client. See {@link #RCS_PROFILE_1_0 },
+ * {@link #RCS_PROFILE_2_3 } or {@link #RCS_PROFILE_2_4 }
* @param clientVendor Identifies the vendor providing the RCS client.
* @param clientVersion Identifies the RCS client version. Refer to GSMA
* RCC.07 "client_version" parameter.
diff --git a/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt b/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt
index 48bfd6f5d33c..62902929fcd5 100644
--- a/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt
+++ b/tests/AttestationVerificationTest/src/android/security/attestationverification/SystemAttestationVerificationTest.kt
@@ -11,10 +11,20 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import com.google.common.truth.Truth.assertThat
+import android.security.attestationverification.AttestationVerificationManager.PARAM_CHALLENGE
+import android.security.attestationverification.AttestationVerificationManager.PROFILE_PEER_DEVICE
import android.security.attestationverification.AttestationVerificationManager.PROFILE_SELF_TRUSTED
-import android.security.attestationverification.AttestationVerificationManager.TYPE_PUBLIC_KEY
+import android.security.attestationverification.AttestationVerificationManager.RESULT_FAILURE
+import android.security.attestationverification.AttestationVerificationManager.RESULT_SUCCESS
import android.security.attestationverification.AttestationVerificationManager.RESULT_UNKNOWN
+import android.security.attestationverification.AttestationVerificationManager.TYPE_PUBLIC_KEY
+import android.security.attestationverification.AttestationVerificationManager.TYPE_CHALLENGE
+import android.security.keystore.KeyGenParameterSpec
+import android.security.keystore.KeyProperties
import java.lang.IllegalArgumentException
+import java.io.ByteArrayOutputStream
+import java.security.KeyPairGenerator
+import java.security.KeyStore
import java.time.Duration
import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit
@@ -23,25 +33,26 @@ import java.util.concurrent.TimeUnit
@SmallTest
@RunWith(AndroidJUnit4::class)
class SystemAttestationVerificationTest {
-
@get:Rule
val rule = ActivityScenarioRule(TestActivity::class.java)
private lateinit var activity: Activity
private lateinit var avm: AttestationVerificationManager
+ private lateinit var androidKeystore: KeyStore
@Before
fun setup() {
rule.getScenario().onActivity {
avm = it.getSystemService(AttestationVerificationManager::class.java)
activity = it
+ androidKeystore = KeyStore.getInstance(ANDROID_KEYSTORE).apply { load(null) }
}
}
@Test
fun verifyAttestation_returnsUnknown() {
val future = CompletableFuture<Int>()
- val profile = AttestationProfile(PROFILE_SELF_TRUSTED)
+ val profile = AttestationProfile(PROFILE_PEER_DEVICE)
avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0),
activity.mainExecutor) { result, _ ->
future.complete(result)
@@ -51,9 +62,82 @@ class SystemAttestationVerificationTest {
}
@Test
- fun verifyToken_returnsUnknown() {
+ fun verifyAttestation_returnsFailureWithEmptyAttestation() {
val future = CompletableFuture<Int>()
val profile = AttestationProfile(PROFILE_SELF_TRUSTED)
+ avm.verifyAttestation(profile, TYPE_CHALLENGE, Bundle(), ByteArray(0),
+ activity.mainExecutor) { result, _ ->
+ future.complete(result)
+ }
+
+ assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE)
+ }
+
+ @Test
+ fun verifyAttestation_returnsFailureWithEmptyRequirements() {
+ val future = CompletableFuture<Int>()
+ val selfTrusted = TestSelfTrustedAttestation("test", "challengeStr")
+ avm.verifyAttestation(selfTrusted.profile, selfTrusted.localBindingType,
+ Bundle(), selfTrusted.attestation, activity.mainExecutor) { result, _ ->
+ future.complete(result)
+ }
+ assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE)
+ }
+
+ @Test
+ fun verifyAttestation_returnsFailureWithWrongBindingType() {
+ val future = CompletableFuture<Int>()
+ val selfTrusted = TestSelfTrustedAttestation("test", "challengeStr")
+ avm.verifyAttestation(selfTrusted.profile, TYPE_PUBLIC_KEY,
+ selfTrusted.requirements, selfTrusted.attestation, activity.mainExecutor) { result, _ ->
+ future.complete(result)
+ }
+ assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE)
+ }
+
+ @Test
+ fun verifyAttestation_returnsFailureWithWrongRequirements() {
+ val future = CompletableFuture<Int>()
+ val selfTrusted = TestSelfTrustedAttestation("test", "challengeStr")
+ val wrongKeyRequirements = Bundle()
+ wrongKeyRequirements.putByteArray(
+ "wrongBindingKey", "challengeStr".encodeToByteArray())
+ avm.verifyAttestation(selfTrusted.profile, selfTrusted.localBindingType,
+ wrongKeyRequirements, selfTrusted.attestation, activity.mainExecutor) { result, _ ->
+ future.complete(result)
+ }
+ assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE)
+ }
+
+ @Test
+ fun verifyAttestation_returnsFailureWithWrongChallenge() {
+ val future = CompletableFuture<Int>()
+ val selfTrusted = TestSelfTrustedAttestation("test", "challengeStr")
+ val wrongChallengeRequirements = Bundle()
+ wrongChallengeRequirements.putByteArray(PARAM_CHALLENGE, "wrong".encodeToByteArray())
+ avm.verifyAttestation(selfTrusted.profile, selfTrusted.localBindingType,
+ wrongChallengeRequirements, selfTrusted.attestation, activity.mainExecutor) {
+ result, _ -> future.complete(result)
+ }
+ assertThat(future.getSoon()).isEqualTo(RESULT_FAILURE)
+ }
+
+ // TODO(b/216144791): Add more failure tests for PROFILE_SELF_TRUSTED.
+ @Test
+ fun verifyAttestation_returnsSuccess() {
+ val future = CompletableFuture<Int>()
+ val selfTrusted = TestSelfTrustedAttestation("test", "challengeStr")
+ avm.verifyAttestation(selfTrusted.profile, selfTrusted.localBindingType,
+ selfTrusted.requirements, selfTrusted.attestation, activity.mainExecutor) { result, _ ->
+ future.complete(result)
+ }
+ assertThat(future.getSoon()).isEqualTo(RESULT_SUCCESS)
+ }
+
+ @Test
+ fun verifyToken_returnsUnknown() {
+ val future = CompletableFuture<Int>()
+ val profile = AttestationProfile(PROFILE_PEER_DEVICE)
avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0),
activity.mainExecutor) { _, token ->
val result = avm.verifyToken(profile, TYPE_PUBLIC_KEY, Bundle(), token, null)
@@ -66,7 +150,7 @@ class SystemAttestationVerificationTest {
@Test
fun verifyToken_tooBigMaxAgeThrows() {
val future = CompletableFuture<VerificationToken>()
- val profile = AttestationProfile(PROFILE_SELF_TRUSTED)
+ val profile = AttestationProfile(PROFILE_PEER_DEVICE)
avm.verifyAttestation(profile, TYPE_PUBLIC_KEY, Bundle(), ByteArray(0),
activity.mainExecutor) { _, token ->
future.complete(token)
@@ -87,4 +171,52 @@ class SystemAttestationVerificationTest {
super.onCreate(savedInstanceState)
}
}
+
+ inner class TestSelfTrustedAttestation(val alias: String, val challenge: String) {
+ val profile = AttestationProfile(PROFILE_SELF_TRUSTED)
+ val localBindingType = TYPE_CHALLENGE
+ val requirements: Bundle
+ val attestation: ByteArray
+
+ init {
+ val challengeByteArray = challenge.encodeToByteArray()
+ generateAndStoreKey(alias, challengeByteArray)
+ attestation = generateCertificatesByteArray(alias)
+ requirements = Bundle()
+ requirements.putByteArray(PARAM_CHALLENGE, challengeByteArray)
+ }
+
+ private fun generateAndStoreKey(alias: String, challenge: ByteArray) {
+ val kpg: KeyPairGenerator = KeyPairGenerator.getInstance(
+ KeyProperties.KEY_ALGORITHM_EC,
+ ANDROID_KEYSTORE
+ )
+ val parameterSpec: KeyGenParameterSpec = KeyGenParameterSpec.Builder(
+ alias,
+ KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
+ ).run {
+ // a challenge results in a generated attestation
+ setAttestationChallenge(challenge)
+ setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
+ build()
+ }
+ kpg.initialize(parameterSpec)
+ kpg.generateKeyPair()
+ }
+
+ private fun generateCertificatesByteArray(alias: String): ByteArray {
+ val pkEntry = androidKeystore.getEntry(alias, null) as KeyStore.PrivateKeyEntry
+ val certs = pkEntry.certificateChain
+ val bos = ByteArrayOutputStream()
+ certs.forEach {
+ bos.write(it.encoded)
+ }
+ return bos.toByteArray()
+ }
+ }
+
+ companion object {
+ private const val TAG = "AVFTEST"
+ private const val ANDROID_KEYSTORE = "AndroidKeyStore"
+ }
}
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index 566c725a3414..98d13e81551d 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -26,8 +26,16 @@
<option name="shell-timeout" value="6600s" />
<option name="test-timeout" value="6600s" />
<option name="hidden-api-checks" value="false" />
+ <option name="device-listeners"
+ value="com.android.server.wm.flicker.TraceFileReadyListener" />
</test>
<metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
+ <option name="pull-pattern-keys" value="(\w)+\.winscope" />
+ <option name="pull-pattern-keys" value="(\w)+\.mp4" />
+ <option name="collect-on-run-ended-only" value="false" />
+ <option name="clean-up" value="true" />
+ </metrics_collector>
+ <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
<option name="directory-keys" value="/sdcard/flicker" />
<option name="collect-on-run-ended-only" value="true" />
<option name="clean-up" value="true" />
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index 8fe00297139a..b66c45c7c9f0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -19,11 +19,13 @@ package com.android.server.wm.flicker.helpers
import android.app.Instrumentation
import android.support.test.launcherhelper.ILauncherStrategy
import android.support.test.launcherhelper.LauncherStrategyFactory
+import android.view.Display
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until
import com.android.server.wm.flicker.testapp.ActivityOptions
import com.android.server.wm.traces.common.FlickerComponentName
+import com.android.server.wm.traces.common.WindowManagerConditionsFactory
import com.android.server.wm.traces.parser.toFlickerComponent
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
@@ -36,6 +38,10 @@ class TwoActivitiesAppHelper @JvmOverloads constructor(
.getInstance(instr)
.launcherStrategy
) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+
+ private val secondActivityComponent =
+ ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME.toFlickerComponent()
+
fun openSecondActivity(device: UiDevice, wmHelper: WindowManagerStateHelper) {
val launchActivityButton = By.res(getPackage(), LAUNCH_SECOND_ACTIVITY)
val button = device.wait(Until.findObject(launchActivityButton), FIND_TIMEOUT)
@@ -47,8 +53,11 @@ class TwoActivitiesAppHelper @JvmOverloads constructor(
button.click()
device.wait(Until.gone(launchActivityButton), FIND_TIMEOUT)
- wmHelper.waitForAppTransitionIdle()
- wmHelper.waitForFullScreenApp(component)
+ wmHelper.waitForFullScreenApp(secondActivityComponent)
+ wmHelper.waitFor(
+ WindowManagerConditionsFactory.isAppTransitionIdle(Display.DEFAULT_DISPLAY),
+ WindowManagerConditionsFactory.hasLayersAnimating().negate()
+ )
}
companion object {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
index 648353e34f92..195af589d77c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -70,7 +70,7 @@ class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) {
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
setup {
- eachRun {
+ test {
testApp.launchViaIntent(wmHelper)
wmHelper.waitForFullScreenApp(testApp.component)
}
diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp
index 41f73cd9c706..228520e8545b 100644
--- a/tests/vcn/Android.bp
+++ b/tests/vcn/Android.bp
@@ -18,6 +18,7 @@ android_test {
"java/**/*.kt",
],
platform_apis: true,
+ defaults: ["framework-connectivity-test-defaults"],
test_suites: ["device-tests"],
certificate: "platform",
static_libs: [
@@ -28,6 +29,7 @@ android_test {
"net-tests-utils",
"platform-test-annotations",
"services.core",
+ "service-connectivity-tiramisu-pre-jarjar",
],
libs: [
"android.test.runner",
diff --git a/tests/vcn/AndroidManifest.xml b/tests/vcn/AndroidManifest.xml
index 2ad9aac67029..a8f657c89f76 100644
--- a/tests/vcn/AndroidManifest.xml
+++ b/tests/vcn/AndroidManifest.xml
@@ -16,7 +16,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.frameworks.tests.vcn">
-
+ <uses-sdk android:minSdkVersion="33"
+ android:targetSdkVersion="33"/>
<application>
<uses-library android:name="android.test.runner" />
</application>